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

   dsuser.c

Abstract:

   Usermode wrapper routines for dstreams api requests.

Author:

   Michael Zarns

--*/
#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "stdlib.h"

#include "dsioctl.h"
#include "dsuser.h"

static CHAR DebugBuffer[4096];

BOOL 
dsvSyncIoRequest( IN HANDLE  hDevice, 
                  IN LONG    Ioctl, 
                  IN PVOID   pInData, 
                  IN ULONG   InDataLength, 
                  IN PVOID   pOutData, 
                  IN ULONG   OutDataLength,
                  OUT PDWORD pError )
{
	BOOL bSuccess;
	DWORD dwBytes;
	OVERLAPPED Ol;
	DWORD Error;

	ZeroMemory( &Ol, sizeof( Ol ) );
	Ol.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
	dwBytes = 0;

	bSuccess = DeviceIoControl( hDevice, Ioctl, 
	                            pInData, InDataLength,
	                            pOutData, OutDataLength,
	                            &dwBytes, &Ol );
	if ( !bSuccess )
	{
		Error = GetLastError();
		if ( Error == ERROR_IO_PENDING )
			bSuccess = GetOverlappedResult( hDevice, &Ol, &dwBytes, TRUE );
		else
		{
		#if DBG
	      sprintf( DebugBuffer, "DeviceIoControl failed, Error %d\n", Error );
	      OutputDebugString( DebugBuffer );
		#endif
		}
	}

	CloseHandle( Ol.hEvent );

	*pError = bSuccess ? 0 : Error;
	return( bSuccess );
}


BOOL 
dsvAsyncIoRequest( HANDLE       hDevice, 
                   LONG         Ioctl, 
                   PVOID        pInData, 
                   ULONG        InDataLength, 
                   PVOID        pOutData, 
                   ULONG        OutDataLength,
                   PDWORD       pdwBytes,
                   LPOVERLAPPED pOl,
                   OUT PDWORD   pError )
{
	BOOL bSuccess;
	DWORD Error;

	bSuccess = DeviceIoControl( hDevice, Ioctl, 
	                            pInData, InDataLength,
	                            pOutData, OutDataLength,
	                            pdwBytes, pOl );

	if ( !bSuccess )
	{
		Error = GetLastError();
		if ( Error != ERROR_IO_PENDING )
		{
			bSuccess = FALSE;
			#if DBG
				sprintf( DebugBuffer, "DeviceIoControl failed, Error %d\n", Error );
				OutputDebugString( DebugBuffer );
			#endif
		}
	}

	*pError = bSuccess ? 0 : Error;
	return( bSuccess );
}


BOOL __cdecl
DsOpen(
	IN HANDLE   hDevice,
	IN CHAR const * const pDeviceName,
	OUT PHANDLE phStream )
/*++

Description:

	This routine performs a synchronous open request to the named device.

Parameters:

	hDevice
		Device handle on which to send this request.

	pDeviceName
		Null-terminated string containing the devicename to open, i.e. "X250".

	phStream
		Address to which the stream handle will be written on successful completion
		of the open request..

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_OPEN Open = {0};
	BOOL bSuccess;
	DWORD Error;

	strncpy( (PVOID)&Open.DeviceName, pDeviceName, DS_DEVICENAME_SIZE );
	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_OPEN,
	                             &Open, sizeof( Open ),
	                             &Open, sizeof( Open ), &Error );
	*phStream = Open.hStream;
	return( bSuccess && !Open.ErrorCode );
}


BOOL __cdecl
DsClose(
	IN HANDLE hDevice,
	IN HANDLE hStream )
/*++

Description:

	Performs a synchronous close request on the stream.

Parameters:

	hDevice
		Device handle on which to send this request.

	hStream
		Handle of stream to close.

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_CLOSE Close = {0};
	BOOL bSuccess;
	DWORD Error;
	Close.hStream = hStream;
	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_CLOSE,
	                             &Close, sizeof Close,
	                             &Close, sizeof Close,
	                             &Error );
	return( bSuccess );
}


BOOL __cdecl
DsPurge(
	IN HANDLE hDevice,
	IN HANDLE hStream,
	IN ULONG  Flags )
/*++

Description:

	Performs a synchronous purge request on the stream.

Parameters:

	hDevice
		Device handle on which to send this request.

	hStream
		Handle of stream to purge.

	Flags
		DS_PURGE flags to pass down.  See DsIoctl.h for details.

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_PURGE Purge = {0};
	BOOL bSuccess;
	DWORD Error;
	Purge.hStream = hStream;
	Purge.Flags   = Flags;
	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_PURGE,
	                             &Purge, sizeof Purge,
	                             &Purge, sizeof Purge, &Error );
	return( bSuccess );
}


BOOL __cdecl
DsIoctl(
	IN HANDLE hDevice,
	IN HANDLE hStream,
	IN ULONG  Command,
	IN PVOID  pData,
	IN ULONG  cbData )

/*++

Description:

	Performs a synchronous ioctl request on the stream.

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_IOCTL Ioctl = {0};
	BOOL bSuccess;
	DWORD Error;

	Ioctl.hStream = hStream;
	Ioctl.Command = Command;
	Ioctl.pDataIn = Ioctl.pDataOut = pData;
	Ioctl.cbDataIn = Ioctl.cbMaxDataOut = cbData;


	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_IOCTL, 
	                             &Ioctl, sizeof Ioctl, 
	                             &Ioctl, sizeof Ioctl, &Error );
	if ( !bSuccess || Error || Ioctl.ReturnValue || Ioctl.ErrorCode )
	{
		#if DBG
	      sprintf( DebugBuffer, "Ioctl failed, bSuccess 0x%x, ReturnVal 0x%x, Error 0x%x\n", bSuccess, Ioctl.ReturnValue, Ioctl.ErrorCode );
	      OutputDebugString( DebugBuffer );
		#endif
		return FALSE;
	}
	return TRUE;
}


BOOL __cdecl
DsPutMsg(
	IN HANDLE      hDevice,
	IN HANDLE      hStream,
	IN PVOID       pControl,
	IN ULONG       cbControl,
	IN PVOID       pData,
	IN ULONG       cbData,
	IN DS_PRIORITY Priority )
/*++

Description:

	Performs a synchronous PutMsg request on the stream.  

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_PUTMSG PutMsg = {0};
	BOOL bSuccess;
	DWORD Error;

	PutMsg.hStream   = hStream;
	PutMsg.pControl  = pControl;
	PutMsg.cbControl = cbControl;
	PutMsg.pData     = pData;
	PutMsg.cbData    = cbData;
	PutMsg.Priority  = Priority;

	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_PUTMSG, 
	                             &PutMsg, sizeof PutMsg, 
	                             &PutMsg, sizeof PutMsg, &Error );
	if ( !bSuccess )
	{
		#if DBG
	      sprintf( DebugBuffer, "PutMsg failed, bSuccess 0x%x\n", bSuccess );
	      OutputDebugString( DebugBuffer );
		#endif
		return FALSE;
	}
	return TRUE;
}


BOOL __cdecl
DsGetMsg(
	IN  HANDLE      hDevice,
	IN  HANDLE      hStream,
	IN  PVOID       pControl,
	IN  ULONG       cbMaxControl,
	OUT PULONG      pcbControl,
	IN  PVOID       pData,
	IN  ULONG       cbMaxData,
	OUT PULONG      pcbData,
	IN  DS_PRIORITY Priority )

/*++

Description:

	Performs a synchronous GetMsg request on the stream.

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_GETMSG GetMsg = {0};
	BOOL bSuccess;
	DWORD Error;

	GetMsg.hStream      = hStream;
	GetMsg.pControl     = pControl;
	GetMsg.cbMaxControl = cbMaxControl;
	GetMsg.pData        = pData;
	GetMsg.cbMaxData    = cbMaxData;
	GetMsg.Priority     = Priority;

	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_GETMSG, 
	                             &GetMsg, sizeof GetMsg, 
	                             &GetMsg, sizeof GetMsg, &Error );
	if ( !bSuccess )
	{
		#if DBG
	      sprintf( DebugBuffer, "GetMsg failed, bSuccess 0x%x\n", bSuccess );
	      OutputDebugString( DebugBuffer );
		#endif
		return FALSE;
	}

	*pcbControl = GetMsg.cbControl;
	*pcbData    = GetMsg.cbData;
	return TRUE;
}


BOOL __cdecl
DsGetMsgEx(
	IN HANDLE       hDevice,
	IN PDS_GETMSG   pGetMsg,
	IN LPOVERLAPPED pOl )

/*++

Description:

	Performs an asynchronous GetMsg request on the stream.  

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	BOOL bSuccess;
	DWORD Error;

	bSuccess = dsvAsyncIoRequest( hDevice, IOCTL_DS_GETMSG, 
	                              pGetMsg, sizeof *pGetMsg, 
	                              pGetMsg, sizeof *pGetMsg, NULL, pOl, &Error );
	if ( !bSuccess )
	{
		#if DBG
	      sprintf( DebugBuffer, "GetMsg failed, bSuccess 0x%x\n", bSuccess );
	      OutputDebugString( DebugBuffer );
		#endif
		return FALSE;
	}
	return TRUE;
}
