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

#include <ntddk.h>
#include <wchar.h>

// Streams Headers
#include "types.h"
#include "wan_proto.h"
#include "wan_control.h"
 
#include "dsapi.h"
#include "dsioctl.h"
#include "dsmp.h"
#include "dgsna.h"
#include "ioctls.h"
#include "pnp.h"
#include "power.h"

#include "digilib.h"
#include "dxbreg.h"

/*
 **		Linked list of the devices
 */

#define DOSDEVICE_PATH      L"\\DosDevices\\"


DEVICE_OBJECT	* DgSnaDevices;
KSPIN_LOCK		gSnaDevicesSpinLock;
DRIVER_OBJECT   * gpDriverObject;

extern NTSTATUS	DgSnaProcessCommands(PDEVICE_OBJECT ,PIRP );
extern NTSTATUS	DgSnaOpen(PDEVICE_OBJECT, PIRP);
extern NTSTATUS	DgSnaClose(PDEVICE_OBJECT,PIRP);
extern VOID 	DgSnaReadRequestDpc(PKDPC pDpc,PVOID context, PVOID sa1, PVOID sa2);



VOID
DgSnaUnload( PDRIVER_OBJECT  pDriverObject)

{
	LIST_ENTRY	  * p;
	PPORT_EXT		pPortExt;
	PDEVICE_OBJECT	pSnaDevice;
	KIRQL			Irql;

	DigiDump(DIGIINIT,("DgSnaUnload: Entry\n"));

		while(DgSnaDevices)
		{
			pSnaDevice		= DgSnaDevices;
			pPortExt		= pSnaDevice->DeviceExtension;
			DgSnaDevices	= pPortExt->nextPort;

			DigiDump(DIGIOPENCLOSE,("DgSnaUnload: Delete Port=%x, Device=%x\n",pPortExt,pSnaDevice));

			{
				UNICODE_STRING SymbolicName = { 0 };
		      
		  		if ( NT_SUCCESS( DigiStrSymbolicName( &SymbolicName, pPortExt->snadeviceName.Buffer ) ) )
				{
					(void) IoDeleteSymbolicLink( &SymbolicName );
					DigiStrFreeUnicodeString( &SymbolicName );
				}
				  	
			}
			IoDeleteDevice(pSnaDevice);
		}

	DigiDump(DIGIINIT,("DgSnaUnload: Exit\n"));
}

VOID
DgSnaRemoveSnaDevice(IN PDEVICE_OBJECT	pSdo
	)

// Note - Future Enhancement*
//
//  This routine could be simplified if the list of devices pointed to the
//  extensions and not the device object.

{
	PPORT_EXT				pCurrentPortExt = NULL;
	PPORT_EXT				pPreviousPortExt = NULL;
	PDEVICE_OBJECT			pSnaDevice;
	PDEVICE_OBJECT			pCurrentSnaDevice;
	PDEVICE_OBJECT			pPreviousSnaDevice;
	PDEVICE_OBJECT			pNextSnaDevice;
	KIRQL					Irql;
	NTSTATUS			Status;

	DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Entry, Device = %x\n",pSdo));
	
	KeAcquireSpinLock(&gSnaDevicesSpinLock,&Irql);

	pPreviousSnaDevice	= DgSnaDevices;
	pCurrentSnaDevice	= DgSnaDevices;

	// The Device will only be in the list if a Link Service is configured for it.
	while(pCurrentSnaDevice)
	{
		DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Loop Current = %x, pPreviousSnaDevice = %x\n",pCurrentSnaDevice,pPreviousSnaDevice));
		pCurrentPortExt = pCurrentSnaDevice->DeviceExtension;

		if (pCurrentSnaDevice == pSdo)
		{

			// Remove the Device from the list
			pNextSnaDevice = pCurrentPortExt->nextPort;

			if (pCurrentSnaDevice == DgSnaDevices)
			{
				DgSnaDevices = pNextSnaDevice;
				DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: DgSnaDevices = %x\n",DgSnaDevices));
			}
			else
			{
				pPreviousPortExt = pPreviousSnaDevice->DeviceExtension;
				pPreviousPortExt->nextPort = pNextSnaDevice;
			}

			break;
		}
		else
		{
			pPreviousSnaDevice	= pCurrentSnaDevice;
			pCurrentSnaDevice	= pCurrentPortExt->nextPort;
		}

	}
	
	KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);

	DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Delete = %x\n",pCurrentSnaDevice));
	ASSERT(pCurrentPortExt != NULL);

	// Clean up the Device
	{
		UNICODE_STRING SymbolicName = { 0 };
      
  		if ( NT_SUCCESS( DigiStrSymbolicName( &SymbolicName, pCurrentPortExt->snadeviceName.Buffer ) ) )
		{
			(void) IoDeleteSymbolicLink( &SymbolicName );
			DigiStrFreeUnicodeString( &SymbolicName );
		}
		  	
	}

	IoDeleteDevice(pSdo);

	DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Exit\n"));
}


NTSTATUS
DgUniStringInit(UNICODE_STRING * pUniString, ULONG size)
{

	NTSTATUS	status = STATUS_SUCCESS;

	pUniString->Length = 0;
	pUniString->MaximumLength = (USHORT) (size * sizeof(WCHAR)) +
										sizeof(WCHAR);		// for termination


	pUniString->Buffer = ExAllocatePool(NonPagedPool, 
										pUniString->MaximumLength);

	if (pUniString->Buffer == NULL)
		{
      status = STATUS_INSUFFICIENT_RESOURCES;
		}
	else
		{
		
		// Zero the Buffer; this will always insure that the buffer can
		// be used as a null terminated string.
		RtlZeroMemory(pUniString->Buffer, pUniString->MaximumLength);

		}

	return status;

}


NTSTATUS
DgSnaGetKey(IN UNICODE_STRING *pPath, OUT UNICODE_STRING *pKeyName, ULONG dgSnaKeyIndex)
{

	HANDLE      dgHandle;					// Handle to a dgsna  key.
	NTSTATUS    status;						// Kernel status return value.
	ULONG       dgKeyInfoLength;			// Size of enumerated key.

	UNICODE_STRING			dgKeyString;    // Unicode string for enumerated key.
	KEY_BASIC_INFORMATION	*dgKeyInfo;     // Registry Key information.
	OBJECT_ATTRIBUTES		dgAttributes;   // Driver's attribute value.

	DigiDump(DIGIINIT,("DgSnaGetKey: Entry path %wZ, dgSnaKeyIndex = %d\n",pPath,dgSnaKeyIndex));

    // Get Driver's attributes to prepare to open the registry key.
    InitializeObjectAttributes(&dgAttributes,
							   pPath, 
							   OBJ_CASE_INSENSITIVE,
							   NULL,
							   NULL);

    // Open the Driver's key.
    status = ZwOpenKey(&dgHandle, KEY_READ, &dgAttributes);
    if (! NT_SUCCESS(status))
    {
		DigiDump(DIGIINIT,("DgSnaGetKey: Could not open key\n"));
        return (status);
    }

    // Get memory to store key info.
    dgKeyInfo = (PKEY_BASIC_INFORMATION)
                ExAllocatePool(NonPagedPool, DGSNA_MAX_PATH_LENGTH);

    if (dgKeyInfo == NULL)
    {
        ZwClose(dgHandle);
		DigiDump(DIGIINIT,("DgSnaGetKey: Insufficient Reources\n"));
		return (STATUS_INSUFFICIENT_RESOURCES);
    }

	DigiDump(DIGIINIT,("DgSnaGetKey: dgSnaKeyIndex = %d\n",dgSnaKeyIndex));

    // Get the Driver's index'th item.  The key is "discovered" in this
    // manner because the keys could be named non-incrementally.
    status = ZwEnumerateKey(dgHandle, dgSnaKeyIndex, KeyBasicInformation, 
                            dgKeyInfo,DGSNA_MAX_PATH_LENGTH , 
                            &dgKeyInfoLength);

    if ((! NT_SUCCESS(status)) ||
        (dgKeyInfoLength > DGSNA_MAX_PATH_LENGTH))
    {

        ZwClose(dgHandle);
        ExFreePool(dgKeyInfo);
		DigiDump(DIGIINIT,("DgSnaGetKey: ZwEnumerateKey failed, %x\n",status));
        return (status);
    }

    // Use dgKeyInfo buffer.
    dgKeyString.Length			= (USHORT) dgKeyInfo->NameLength;
    dgKeyString.MaximumLength	= (USHORT) dgKeyInfo->NameLength;
    dgKeyString.Buffer			= (PWSTR) dgKeyInfo->Name;

    // Deliminate the Key 
    (void) RtlAppendUnicodeToString(pPath, L"\\");

    // Point Key at the Driver's subkey of DgSnaAdapters.
    pKeyName->Length		= dgKeyString.Length;
    pKeyName->MaximumLength = dgKeyString.MaximumLength;
    pKeyName->Buffer		= pPath->Buffer + (pPath->Length / sizeof(WCHAR));

    // Append the key onto the Driver's Registry path to be used to
    // traverse the  subkey .
    (void) RtlAppendUnicodeStringToString(pPath, &dgKeyString);

    // Cleanup before exiting.
    ZwClose(dgHandle);
    ExFreePool(dgKeyInfo);

	DigiDump(DIGIINIT,("DgSnaGetKey: Entry path %wZ\n",pPath));

	return (STATUS_SUCCESS);

}


DgSnaGetAdapterKeyValues(PUNICODE_STRING pPath, 
								  PORT_EXT * pDeviceExtension)
{

RTL_QUERY_REGISTRY_TABLE	dgSnaInfo[4];
RTL_QUERY_REGISTRY_TABLE	portInfo[6];
UNICODE_STRING				linePathDigiSNA;
UNICODE_STRING				linePath;
UNICODE_STRING				deviceName;
UNICODE_STRING				linkServicePath;
ANSI_STRING					ansiString;
NTSTATUS					status = STATUS_SUCCESS;
ULONG						snid;
ULONG						zero = 0;

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues :Entry path %wZ\n",	pPath));

	status = DgUniStringInit(&linkServicePath,DGSNA_MAX_PATH_LENGTH);

	if (! NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init linkServicePath Failed Status = %x\n",status));
		goto Exit;
	}

	status = DgUniStringInit(&deviceName,DGSNA_MAX_PATH_LENGTH);

	if (! NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init deviceName Failed Status = %x\n",status));
		ExFreePool(linkServicePath.Buffer);
		goto Exit;
	}

	status = DgUniStringInit(&linePathDigiSNA,DGSNA_MAX_PATH_LENGTH);

	if (! NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init linePathDigiSNA Failed Status = %x\n",status));
		ExFreePool(linkServicePath.Buffer);
		ExFreePool(deviceName.Buffer);
		goto Exit;
	}

   	RtlZeroMemory(dgSnaInfo, sizeof(dgSnaInfo));
   
	dgSnaInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	dgSnaInfo[0].Name			= L"DigiDxbPath";
	dgSnaInfo[0].EntryContext	= &linePathDigiSNA ;

	dgSnaInfo[1].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	dgSnaInfo[1].Name			= L"Device";
	dgSnaInfo[1].EntryContext	= &pDeviceExtension->symbolicName ;

   
	dgSnaInfo[2].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	dgSnaInfo[2].Name			= L"LinkServicePath";
	dgSnaInfo[2].EntryContext	= &linkServicePath ;
   
	status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, pPath->Buffer, 
                                        dgSnaInfo, NULL, NULL);

	
	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : pPath Query Registry Failed Status = %x\n",status));
		goto cleanUpAndExit;
	}

	// Add the OS Specific DSAPI Adapter Path onto the Line Path
	status = DigiStrAllocUnicodeString( &linePath, DXB_REDIRECTPATH_ROOT, linePathDigiSNA.Buffer, NULL );

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : linePath  = %wZ\n",&linePath));

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init linePath Failed Status = %x\n",status));
		goto cleanUpAndExit;
	}

	RtlZeroMemory(portInfo, sizeof(portInfo));


	portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	portInfo[0].Name			= L"Device";
	portInfo[0].EntryContext	= &pDeviceExtension->adapterName ;

	status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
									linePath.Buffer, 
                                    portInfo,
									NULL,
									NULL);

	if (!NT_SUCCESS(status)) {

		RtlZeroMemory(portInfo, sizeof(portInfo));

		portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
									  RTL_QUERY_REGISTRY_REQUIRED;
		portInfo[0].Name			= L"Adapter";
		portInfo[0].EntryContext	= &pDeviceExtension->adapterName ;

		status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
									linePath.Buffer, 
                                    portInfo,
									NULL,
									NULL);
		if (!NT_SUCCESS(status))
		{
			DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : No Device or Adapter Status = %x\n",status));
			goto cleanUpAndExit;
		}

	}		

	RtlZeroMemory(portInfo, sizeof(portInfo));

    portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
					              RTL_QUERY_REGISTRY_REQUIRED;
	portInfo[0].Name			= L"LineName";
	portInfo[0].EntryContext	= &deviceName ;

	portInfo[1].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	portInfo[1].Name			= L"Snid";
	portInfo[1].EntryContext	= &snid ;

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : DxbPath %ws\n",linePath.Buffer));

	status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
									linePath.Buffer, 
                                    portInfo,
									NULL,
									NULL);

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : RtlQueryRegistryValues failed status %x\n",status));
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : len adptrname %x linename %x snid %x\n",portInfo[0].DefaultLength,portInfo[1].DefaultLength,  portInfo[2].DefaultLength));

		goto cleanUpAndExit;
	}

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Adaptername %wZ lineName %wZ  snid %x status - %x\n",&pDeviceExtension->adapterName, &deviceName,snid, status));
	
	ansiString.Buffer			= pDeviceExtension->deviceName;
	ansiString.Length			= 0;
	ansiString.MaximumLength	= deviceName.MaximumLength;

	RtlUnicodeStringToAnsiString(&ansiString,&deviceName,
										  FALSE);

	pDeviceExtension->snid =  snid ;

	// get the lineservice parameters
	RtlZeroMemory(portInfo, sizeof(portInfo));

	portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[0].Name			= L"InternalClock";
	portInfo[0].EntryContext	= &pDeviceExtension->internalClocking ;
	portInfo[0].DefaultType		= REG_DWORD;
	portInfo[0].DefaultData		= &zero;
	portInfo[0].DefaultLength	= sizeof(pDeviceExtension->internalClocking);

	portInfo[1].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[1].Name			= L"LineSpeed";
	portInfo[1].EntryContext	= &pDeviceExtension->lineSpeed ;
	portInfo[1].DefaultType		= REG_DWORD;
	portInfo[1].DefaultData		= &zero;
	portInfo[1].DefaultLength	= sizeof(pDeviceExtension->lineSpeed);

	portInfo[2].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[2].Name			= L"LineType";
	portInfo[2].EntryContext	= &pDeviceExtension->lineType ;
	portInfo[2].DefaultType		= REG_DWORD;
	portInfo[2].DefaultData		= &zero;
	portInfo[2].DefaultLength	= sizeof(pDeviceExtension->lineType );

	portInfo[3].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[3].Name			= L"Carrier";
	portInfo[3].EntryContext	= &pDeviceExtension->constantRTS ;
	portInfo[3].DefaultType		= REG_DWORD;
	portInfo[3].DefaultData		= &zero;
	portInfo[3].DefaultLength	= sizeof(pDeviceExtension->constantRTS );

	portInfo[4].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[4].Name			= L"IBMCSNT";
	portInfo[4].EntryContext	= &pDeviceExtension->ibmComServer ;
	portInfo[4].DefaultType		= REG_DWORD;
	portInfo[4].DefaultData		= &zero;
	portInfo[4].DefaultLength	= sizeof(pDeviceExtension->ibmComServer );

	
	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : LinkServicePath %wZ\n",&linkServicePath));
		
	status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
									linkServicePath.Buffer, 
									portInfo,
									NULL,
									NULL);

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : AdapterKeyValues\n\tSnid %x %c\n\tDeviceName %wZ \
						\n\tLineName %s\n\tAdapterName %wZ  \n\t linespeed %d %x \n\t \
						lineType %x %d\n\t InternalClock %d %x\n",
						pDeviceExtension->snid,
						(UCHAR) pDeviceExtension->snid,
						&pDeviceExtension->symbolicName,
						pDeviceExtension->deviceName,
						&pDeviceExtension->adapterName,
						pDeviceExtension->lineSpeed,
						pDeviceExtension->lineSpeed,
						pDeviceExtension->lineType,
						pDeviceExtension->lineType,
						pDeviceExtension->internalClocking,
						pDeviceExtension->internalClocking));

	
cleanUpAndExit:


	DigiStrFreeUnicodeString( &linePath );
	ExFreePool(linkServicePath.Buffer);
	ExFreePool(linePathDigiSNA.Buffer);
	ExFreePool(deviceName.Buffer);
			
Exit:

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Exit Status = %x\n",status));

	return status;
	
}


NTSTATUS
DgSnaInitializeDevice(	IN	UNICODE_STRING	* pdeviceName,
						IN	DRIVER_OBJECT	* pDriverObject,
						IN  PDEVICE_OBJECT	* ppDeviceObject

)

{

	UNICODE_STRING				symbolicName	= {0};
	UNICODE_STRING				deviceName		= {0};
	UNICODE_STRING				uniTemp			= {0};
	NTSTATUS					status;
	DEVICE_OBJECT				* pSnaAdapter;
	PORT_EXT					* pDgSnaAdapterExt;
	ULONG						i;
	KIRQL						Irql;

	DigiDump(DIGIINIT,("DgSnaInitializeDevice : Entry  pdeviceName = %wZ, pDriverObject = %x\n",
													pdeviceName,pDriverObject));
	
	RtlInitUnicodeString( &deviceName, NULL );
	status = DigiStrDeviceName( &deviceName, pdeviceName->Buffer );

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaInitializeDevice : Init deviceName Failed Status = %x\n",status));
		goto Exit;
	}

	DigiDump(DIGIINIT,("DgSnaInitializeDevice : FindAdapters Creating %wZ\n",&deviceName));

	status = IoCreateDevice(pDriverObject,
			                sizeof (PORT_EXT),
							&deviceName,
							FILE_DEVICE_DS,
							0,
							FALSE,
							&pSnaAdapter);

	DigiDump(DIGIINIT,("DgSnaInitializeDevice : FindAdapters Created %wZ status %x\n",&deviceName,status));
			
	if (NT_SUCCESS(status))
	{
		pDgSnaAdapterExt = pSnaAdapter->DeviceExtension;
		pDgSnaAdapterExt->pDeviceObject = pSnaAdapter;

		InitializeListHead(&pDgSnaAdapterExt->readBuffers);
		InitializeListHead(&pDgSnaAdapterExt->pendedReadBuffers);
		InitializeListHead(&pDgSnaAdapterExt->completedReadBuffers);
		InitializeListHead(&pDgSnaAdapterExt->writeBuffers);
		InitializeListHead(&pDgSnaAdapterExt->pendedWriteBuffers);

		// Initialize the Close Event
		KeInitializeEvent( &pDgSnaAdapterExt->evClose, NotificationEvent, FALSE );

		for(i=0;i<DGSNA_MAX_READ_ENTRIES;++i)
		{
			InsertHeadList(&pDgSnaAdapterExt->readBuffers,
						   &(pDgSnaAdapterExt->readListEntryArray[i].listEntry));

			DigiDump(DIGIINIT,("DgSnaInitializeDevice :read entry %d %x\n",i,&pDgSnaAdapterExt->readListEntryArray[i].listEntry));

			pDgSnaAdapterExt->readListEntryArray[i].pPortExt = pDgSnaAdapterExt;
			pDgSnaAdapterExt->readListEntryArray[i].bufferSize = DGSNA_MAX_PACKET_SIZE;

		}

		for(i=0;i<DGSNA_MAX_WRITE_ENTRIES;++i)
		{
			InsertHeadList(&pDgSnaAdapterExt->writeBuffers,
						   &(pDgSnaAdapterExt->writeListEntryArray[i].listEntry));

			DigiDump(DIGIINIT,("DgSnaInitializeDevice :write entry %d %x\n",i,&pDgSnaAdapterExt->writeListEntryArray[i].listEntry));

			pDgSnaAdapterExt->writeListEntryArray[i].pPortExt = pDgSnaAdapterExt;
			pDgSnaAdapterExt->writeListEntryArray[i].bufferSize = DGSNA_MAX_PACKET_SIZE;

		}


		KeInitializeDpc(&pDgSnaAdapterExt->dpcReadRequest,
						DgSnaReadRequestDpc,
						pDgSnaAdapterExt);

		KeInitializeTimer(&pDgSnaAdapterExt->readRequestTimer);

		pDgSnaAdapterExt->readRequestTimeout = RtlConvertLongToLargeInteger(DGSNA_READ_REQ_TIMEOUT * -1);

		KeInitializeSpinLock(&pDgSnaAdapterExt->ownership);

		pDgSnaAdapterExt->symbolicName.Length			= 0;
		pDgSnaAdapterExt->symbolicName.Buffer			= pDgSnaAdapterExt->symbolicNameBuffer;
		pDgSnaAdapterExt->symbolicName.MaximumLength	= sizeof(pDgSnaAdapterExt->symbolicNameBuffer);
			 

		pDgSnaAdapterExt->adapterName.Buffer			= pDgSnaAdapterExt->adapterNameBuffer;
		pDgSnaAdapterExt->adapterName.Length			= 0;		
		pDgSnaAdapterExt->adapterName.MaximumLength		= sizeof(pDgSnaAdapterExt->adapterNameBuffer);
				
		pDgSnaAdapterExt->snadeviceName.Buffer			= pDgSnaAdapterExt->snadeviceNameBuffer;
		pDgSnaAdapterExt->snadeviceName.Length			= 0;		
		pDgSnaAdapterExt->snadeviceName.MaximumLength	= sizeof(pDgSnaAdapterExt->snadeviceNameBuffer);
			  	
		status = DigiStrSymbolicName( &symbolicName, pdeviceName->Buffer );

		if ( NT_SUCCESS( status ) )
		{
			RtlCopyUnicodeString( &pDgSnaAdapterExt->symbolicName, &symbolicName );
			RtlCopyUnicodeString( &pDgSnaAdapterExt->snadeviceName, pdeviceName );
	
			DigiDump(DIGIINIT,("DgSnaFindAdapters : FindAdapters Creating  %wZ\n",&symbolicName));

			status = IoCreateSymbolicLink(&symbolicName, &deviceName);

			if ( NT_SUCCESS( status ) )
			{

				DigiDump(DIGIINIT,("DgSnaInitializeDevice : FindAdapters Created  %wZ status %x\n",&symbolicName,status));

				// Add the Device to the Global List
				KeAcquireSpinLock(&gSnaDevicesSpinLock,&Irql);			
				pDgSnaAdapterExt->nextPort = DgSnaDevices;
				DgSnaDevices = pSnaAdapter;
	 			KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);

				if (ppDeviceObject)
				{
					*ppDeviceObject = pSnaAdapter;
				}
			}			
		}
     
	} //if

	if (symbolicName.Buffer)
		DigiStrFreeUnicodeString( &symbolicName );

	if (deviceName.Buffer)
		DigiStrFreeUnicodeString( &deviceName );

Exit:
	return status;

}


NTSTATUS
DgSnaFindAndInitTheLinkService(	IN UNICODE_STRING	* pDeviceName,
								IN PORT_EXT			* pDeviceExtension
)
{

	UNICODE_STRING				LinkServiceRegPath;
	UNICODE_STRING				LinkServiceRegPathTemp;
	UNICODE_STRING				keyName ;
	NTSTATUS					status = STATUS_SUCCESS;
	
	ULONG						keyIndex = 0;
	ULONG						dgSnaKeyIndex = 0;
	HANDLE						hkAdapter;
	
	DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Entry Device = %S\n",pDeviceName->Buffer));


	status = DigiStrAllocUnicodeString( &LinkServiceRegPathTemp,
										L"\\REGISTRY\\Machine\\System\\CurrentControlSet\\SERVICES\\DigiSNA",
										L"\\Parameters\\LinkServices",
										NULL );

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Init LinkServiceRegPathTemp Failed Status = %x\n",status));
		goto Exit;
	}

	status = DgUniStringInit(&LinkServiceRegPath,LinkServiceRegPathTemp.MaximumLength +
									 DGSNA_MAX_PATH_LENGTH);


	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Init LinkServiceRegPath Failed Status = %x\n",status));
		goto Exit;
	}
	
  	RtlAppendUnicodeStringToString(&LinkServiceRegPath,&LinkServiceRegPathTemp);

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Init LinkServiceRegpath Failed Status = %x\n",status));
		goto Exit;
	}
	
	while (1)
	{

		status = DgSnaGetKey(&LinkServiceRegPath,&keyName,dgSnaKeyIndex);

		// Here the path is complete pathname including
		// the subkey under the services key for  the SNA

		if (status == STATUS_NO_MORE_ENTRIES || !NT_SUCCESS(status))
		{
			break;
		}

		DigiDump(DIGIPNP,("DIGISNA!DgSnaFindAndInitTheLinkService: LinkServiceRegPath = %S, keyname = %S\n",
																	LinkServiceRegPath.Buffer,
																	keyName.Buffer));

		// Get the Device Name
		status = DigiRegOpenKey( &hkAdapter, LinkServiceRegPath.Buffer );

		// Find the Unique Name for the SNA device and that matches the input device.
		if ( NT_SUCCESS( status ) )
		{

			UNICODE_STRING		SnaDevice = {0};

			status = DigiRegQuerySz( hkAdapter, L"Device", &SnaDevice, DigiRegFlagRequired, NULL );

			DigiRegCloseKey(hkAdapter);

	 		if (!NT_SUCCESS(status))
			{
				break;
			}

			if(!RtlCompareUnicodeString(&SnaDevice, pDeviceName, TRUE))
			{  
				// Initialize the Link Service
				status = DgSnaGetAdapterKeyValues(&LinkServiceRegPath,pDeviceExtension);
				break;
			}

		}
		else
		{
			DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Device name not present Status = %x\n",status));
			break;
		}

		// Loop Control
		dgSnaKeyIndex++;
		LinkServiceRegPath.Length = LinkServiceRegPath.Length - (keyName.Length + sizeof(WCHAR));
		keyName.Length = 0;
	
	}  // while


Exit:

	if ( LinkServiceRegPath.Buffer )
			ExFreePool(LinkServiceRegPath.Buffer);

	if ( LinkServiceRegPathTemp.Buffer )
		DigiStrFreeUnicodeString( &LinkServiceRegPathTemp );

	return status;
	
}


NTSTATUS
DgSnaFindAdapters(	IN UNICODE_STRING	* registryPath,
					IN DRIVER_OBJECT	* pDriverObject
)
{

	UNICODE_STRING				path;
	UNICODE_STRING				keyName ;
	NTSTATUS					status = STATUS_SUCCESS;
	
	ULONG						keyIndex = 0;
	ULONG						dgSnaKeyIndex = 0;
	HANDLE						hkAdapter;
	
	DigiDump(DIGIINIT,("DgSnaFindAdapters : Entry\n"));

	status = DgUniStringInit(&path,registryPath->MaximumLength +
									 DGSNA_MAX_PATH_LENGTH);


	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAdapters : Init path Failed Status = %x\n",status));
		goto Exit;
	}
	

  	RtlAppendUnicodeStringToString(&path,registryPath);
	RtlAppendUnicodeToString(&path,L"\\Parameters\\LinkServices");
	
	while (1)
	{
		RTL_QUERY_REGISTRY_TABLE	dgSnaInfo[2];

		status = DgSnaGetKey(&path,&keyName,dgSnaKeyIndex);

		// Here the path is complete pathname including
		// the subkey under the services key for  the SNA

		if (status == STATUS_NO_MORE_ENTRIES)
		{
			status = STATUS_SUCCESS;
			break;
		}

		if (!NT_SUCCESS(status))
		{
			break;
		}

		// Get the Device Name
		status = DigiRegOpenKey( &hkAdapter, path.Buffer );

		DigiDump(DIGIPNP,("DIGISNA!DgSnaFindAdapters: path = %S\n",path.Buffer));

		// Find the Unique Name for the SNA device and Open the Device.
		if ( NT_SUCCESS( status ) )
		{

			UNICODE_STRING		SnaDevice = {0};

			status = DigiRegQuerySz( hkAdapter, L"Device", &SnaDevice, DigiRegFlagRequired, NULL );

			DigiRegCloseKey(hkAdapter);

	 		if (!NT_SUCCESS(status))
			{
				break;
			}

			// Initialize the Device
			status = DgSnaInitializeDevice(&SnaDevice,pDriverObject,NULL);
			DigiStrFreeUnicodeString( &SnaDevice );
			if (!NT_SUCCESS(status))
			{
				break;
			}

		}
		else
		{
			DigiDump(DIGIINIT,("DgSnaFindAdapters : Device name not present Status = %x\n",status));
			break;
		}

		// Loop Control
		dgSnaKeyIndex++;
		path.Length = path.Length - (keyName.Length + sizeof(WCHAR));
		keyName.Length = 0;
	
	}  // while

	ExFreePool(path.Buffer);

Exit:
	return status;
	
}



NTSTATUS
DriverEntry(
    IN DRIVER_OBJECT    *DriverObject,
    IN UNICODE_STRING   *RegistryPath
)

{

	NTSTATUS	status = STATUS_SUCCESS;

	// Set up the debug globals
	DigiDebugInit( RegistryPath,
		(DIGIOPENCLOSE | DIGIPNP | DIGIINIT),
		 DEBUGMODE_ANY
		 );

	DigiDump(DIGIINIT,("DIGISNA DriverEntry : Enter\n"));

	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]	= DgSnaProcessCommands;
	DriverObject->MajorFunction[IRP_MJ_CREATE]			= DgSnaOpen;
	DriverObject->MajorFunction[IRP_MJ_CLOSE]			= DgSnaClose;
	DriverObject->DriverUnload							= DgSnaUnload;

#if NT5_BUILD
	DriverObject->MajorFunction[IRP_MJ_PNP]             = DgSnaDevicePnp;
	DriverObject->MajorFunction[IRP_MJ_POWER]           = DgSnaDevicePower;
	DriverObject->DriverExtension->AddDevice            = DgSnaAddDevice;
#else
	
	status = DgSnaFindAdapters(RegistryPath, DriverObject);

#endif

	gpDriverObject = DriverObject;
	KeInitializeSpinLock(&gSnaDevicesSpinLock);

	DigiDump(DIGIINIT,("DIGISNA DriverEntry : Exit = %x\n",gpDriverObject));

	return (status);


}

