Blame winpr/libwinpr/comm/comm.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Serial Communication API
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 O.S. Systems Software Ltda.
Packit 1fb8d4
 * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
Packit 1fb8d4
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2014 Hewlett-Packard Development Company, L.P.
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined __linux__ && !defined ANDROID
Packit 1fb8d4
Packit 1fb8d4
#include <assert.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <fcntl.h>
Packit 1fb8d4
#include <pthread.h>
Packit 1fb8d4
#include <stdarg.h>
Packit 1fb8d4
#include <sys/ioctl.h>
Packit 1fb8d4
#include <sys/stat.h>
Packit 1fb8d4
#include <sys/types.h>
Packit 1fb8d4
#include <termios.h>
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/comm.h>
Packit 1fb8d4
#include <winpr/tchar.h>
Packit 1fb8d4
#include <winpr/wlog.h>
Packit 1fb8d4
#include <winpr/handle.h>
Packit 1fb8d4
Packit 1fb8d4
#include "comm_ioctl.h"
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Communication Resources:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363196/
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#include "comm.h"
Packit 1fb8d4
Packit 1fb8d4
static wLog* _Log = NULL;
Packit 1fb8d4
Packit 1fb8d4
struct comm_device
Packit 1fb8d4
{
Packit 1fb8d4
	LPTSTR name;
Packit 1fb8d4
	LPTSTR path;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
typedef struct comm_device COMM_DEVICE;
Packit 1fb8d4
Packit 1fb8d4
/* FIXME: get a clever data structure, see also io.h functions */
Packit 1fb8d4
/* _CommDevices is a NULL-terminated array with a maximun of COMM_DEVICE_MAX COMM_DEVICE */
Packit Service 5a9772
#define COMM_DEVICE_MAX 128
Packit 1fb8d4
static COMM_DEVICE** _CommDevices = NULL;
Packit 1fb8d4
static CRITICAL_SECTION _CommDevicesLock;
Packit 1fb8d4
Packit 1fb8d4
static HANDLE_CREATOR _CommHandleCreator;
Packit 1fb8d4
Packit 1fb8d4
static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT;
Packit 1fb8d4
Packit 1fb8d4
static int CommGetFd(HANDLE handle)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_COMM* comm = (WINPR_COMM*)handle;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommIsHandled(handle))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return comm->fd;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
HANDLE_CREATOR* GetCommHandleCreator(void)
Packit 1fb8d4
{
Packit 1fb8d4
	_CommHandleCreator.IsHandled = IsCommDevice;
Packit 1fb8d4
	_CommHandleCreator.CreateFileA = CommCreateFileA;
Packit 1fb8d4
	return &_CommHandleCreator;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void _CommInit(void)
Packit 1fb8d4
{
Packit 1fb8d4
	/* NB: error management to be done outside of this function */
Packit 1fb8d4
	assert(_Log == NULL);
Packit 1fb8d4
	assert(_CommDevices == NULL);
Packit 1fb8d4
	_CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX + 1, sizeof(COMM_DEVICE*));
Packit 1fb8d4
Packit 1fb8d4
	if (!_CommDevices)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (!InitializeCriticalSectionEx(&_CommDevicesLock, 0, 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(_CommDevices);
Packit 1fb8d4
		_CommDevices = NULL;
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	_Log = WLog_Get("com.winpr.comm");
Packit 1fb8d4
	assert(_Log != NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Returns TRUE when the comm module is correctly intialized, FALSE otherwise
Packit 1fb8d4
 * with ERROR_DLL_INIT_FAILED set as the last error.
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL CommInitialized()
Packit 1fb8d4
{
Packit 1fb8d4
	if (pthread_once(&_CommInitialized, _CommInit) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_DLL_INIT_FAILED);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void CommLog_Print(DWORD level, ...)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	va_list ap;
Packit 1fb8d4
	va_start(ap, level);
Packit 1fb8d4
	WLog_PrintVA(_Log, level, ap);
Packit 1fb8d4
	va_end(ap);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL SetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_DLL_INIT_FAILED
Packit 1fb8d4
 *   ERROR_INVALID_HANDLE
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	DWORD bytesReturned;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, lpCommProp,
Packit Service 5a9772
	                         sizeof(COMMPROP), &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "GetCommProperties failure.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 *
Packit 1fb8d4
 *
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_INVALID_HANDLE
Packit 1fb8d4
 *   ERROR_INVALID_DATA
Packit 1fb8d4
 *   ERROR_IO_DEVICE
Packit 1fb8d4
 *   ERROR_OUTOFMEMORY
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL GetCommState(HANDLE hFile, LPDCB lpDCB)
Packit 1fb8d4
{
Packit 1fb8d4
	DCB* lpLocalDcb;
Packit 1fb8d4
	struct termios currentState;
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	DWORD bytesReturned;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!lpDCB)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_DATA);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->DCBlength < sizeof(DCB))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_DATA);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (tcgetattr(pComm->fd, &currentState) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_IO_DEVICE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	lpLocalDcb = (DCB*)calloc(1, lpDCB->DCBlength);
Packit 1fb8d4
Packit 1fb8d4
	if (lpLocalDcb == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_OUTOFMEMORY);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* error_handle */
Packit 1fb8d4
	lpLocalDcb->DCBlength = lpDCB->DCBlength;
Packit 1fb8d4
	SERIAL_BAUD_RATE baudRate;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &baudRate,
Packit 1fb8d4
	                         sizeof(SERIAL_BAUD_RATE), &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the baud rate.");
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	lpLocalDcb->BaudRate = baudRate.BaudRate;
Packit 1fb8d4
	lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!lpLocalDcb->fBinary)
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "Unexpected nonbinary mode, consider to unset the ICANON flag.");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0;
Packit 1fb8d4
	SERIAL_HANDFLOW handflow;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow,
Packit 1fb8d4
	                         sizeof(SERIAL_HANDFLOW), &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the handflow settings.");
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0;
Packit Service 5a9772
	lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0;
Packit 1fb8d4
Packit 1fb8d4
	if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
Packit 1fb8d4
	{
Packit 1fb8d4
		lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL)
Packit 1fb8d4
	{
Packit 1fb8d4
		lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0;
Packit 1fb8d4
	lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0;
Packit 1fb8d4
	lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0;
Packit 1fb8d4
	lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0;
Packit 1fb8d4
	lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0;
Packit 1fb8d4
	lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0;
Packit 1fb8d4
Packit 1fb8d4
	if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
Packit 1fb8d4
	{
Packit 1fb8d4
		lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (handflow.FlowReplace & SERIAL_RTS_CONTROL)
Packit 1fb8d4
	{
Packit 1fb8d4
		lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	// FIXME: how to get the RTS_CONTROL_TOGGLE state? Does it match the UART 16750's Autoflow
Packit Service 5a9772
	// Control Enabled bit in its Modem Control Register (MCR)
Packit Service 5a9772
	lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0;
Packit 1fb8d4
	/* lpLocalDcb->fDummy2 not used */
Packit 1fb8d4
	lpLocalDcb->wReserved = 0; /* must be zero */
Packit 1fb8d4
	lpLocalDcb->XonLim = handflow.XonLimit;
Packit 1fb8d4
	lpLocalDcb->XoffLim = handflow.XoffLimit;
Packit 1fb8d4
	SERIAL_LINE_CONTROL lineControl;
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl,
Packit Service 5a9772
	                         sizeof(SERIAL_LINE_CONTROL), &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the control settings.");
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	lpLocalDcb->ByteSize = lineControl.WordLength;
Packit 1fb8d4
	lpLocalDcb->Parity = lineControl.Parity;
Packit 1fb8d4
	lpLocalDcb->StopBits = lineControl.StopBits;
Packit 1fb8d4
	SERIAL_CHARS serialChars;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars,
Packit 1fb8d4
	                         sizeof(SERIAL_CHARS), &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the serial chars.");
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	lpLocalDcb->XonChar = serialChars.XonChar;
Packit 1fb8d4
	lpLocalDcb->XoffChar = serialChars.XoffChar;
Packit 1fb8d4
	lpLocalDcb->ErrorChar = serialChars.ErrorChar;
Packit 1fb8d4
	lpLocalDcb->EofChar = serialChars.EofChar;
Packit 1fb8d4
	lpLocalDcb->EvtChar = serialChars.EventChar;
Packit 1fb8d4
	memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength);
Packit 1fb8d4
	free(lpLocalDcb);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
error_handle:
Packit 1fb8d4
	free(lpLocalDcb);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * @return TRUE on success, FALSE otherwise.
Packit 1fb8d4
 *
Packit 1fb8d4
 * As of today, SetCommState() can fail half-way with some settings
Packit 1fb8d4
 * applied and some others not. SetCommState() returns on the first
Packit 1fb8d4
 * failure met. FIXME: or is it correct?
Packit 1fb8d4
 *
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_INVALID_HANDLE
Packit 1fb8d4
 *   ERROR_IO_DEVICE
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
Packit 1fb8d4
{
Packit 1fb8d4
	struct termios upcomingTermios;
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	DWORD bytesReturned;
Packit 1fb8d4
Packit 1fb8d4
	/* FIXME: validate changes according GetCommProperties? */
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!lpDCB)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_DATA);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* NB: did the choice to call ioctls first when available and
Packit 1fb8d4
	   then to setup upcomingTermios. Don't mix both stages. */
Packit 1fb8d4
	/** ioctl calls stage **/
Packit 1fb8d4
	SERIAL_BAUD_RATE baudRate;
Packit 1fb8d4
	baudRate.BaudRate = lpDCB->BaudRate;
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate, sizeof(SERIAL_BAUD_RATE),
Packit Service 5a9772
	                         NULL, 0, &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the baud rate.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SERIAL_CHARS serialChars;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars,
Packit 1fb8d4
	                         sizeof(SERIAL_CHARS), &bytesReturned,
Packit 1fb8d4
	                         NULL)) /* as of today, required for BreakChar */
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "SetCommState failure: could not get the initial serial chars.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	serialChars.XonChar = lpDCB->XonChar;
Packit 1fb8d4
	serialChars.XoffChar = lpDCB->XoffChar;
Packit 1fb8d4
	serialChars.ErrorChar = lpDCB->ErrorChar;
Packit 1fb8d4
	serialChars.EofChar = lpDCB->EofChar;
Packit 1fb8d4
	serialChars.EventChar = lpDCB->EvtChar;
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars, sizeof(SERIAL_CHARS),
Packit Service 5a9772
	                         NULL, 0, &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the serial chars.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SERIAL_LINE_CONTROL lineControl;
Packit 1fb8d4
	lineControl.StopBits = lpDCB->StopBits;
Packit 1fb8d4
	lineControl.Parity = lpDCB->Parity;
Packit 1fb8d4
	lineControl.WordLength = lpDCB->ByteSize;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_LINE_CONTROL, &lineControl,
Packit 1fb8d4
	                         sizeof(SERIAL_LINE_CONTROL), NULL, 0, &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the control settings.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SERIAL_HANDFLOW handflow;
Packit 1fb8d4
	ZeroMemory(&handflow, sizeof(SERIAL_HANDFLOW));
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fOutxCtsFlow)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fOutxDsrFlow)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	switch (lpDCB->fDtrControl)
Packit 1fb8d4
	{
Packit 1fb8d4
		case SERIAL_DTR_HANDSHAKE:
Packit 1fb8d4
			handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case SERIAL_DTR_CONTROL:
Packit 1fb8d4
			handflow.ControlHandShake |= DTR_CONTROL_ENABLE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case DTR_CONTROL_DISABLE:
Packit 1fb8d4
			/* do nothing since handflow is init-zeroed */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit Service 5a9772
			CommLog_Print(WLOG_WARN, "Unexpected fDtrControl value: %" PRIu32 "\n",
Packit 1fb8d4
			              lpDCB->fDtrControl);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fDsrSensitivity)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fTXContinueOnXoff)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.FlowReplace |= SERIAL_XOFF_CONTINUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fOutX)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fInX)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.FlowReplace |= SERIAL_AUTO_RECEIVE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fErrorChar)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.FlowReplace |= SERIAL_ERROR_CHAR;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fNull)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.FlowReplace |= SERIAL_NULL_STRIPPING;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	switch (lpDCB->fRtsControl)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RTS_CONTROL_TOGGLE:
Packit 1fb8d4
			CommLog_Print(WLOG_WARN, "Unsupported RTS_CONTROL_TOGGLE feature");
Packit 1fb8d4
			// FIXME: see also GetCommState()
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CONTROL_HANDSHAKE:
Packit 1fb8d4
			handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CONTROL_ENABLE:
Packit 1fb8d4
			handflow.FlowReplace |= SERIAL_RTS_CONTROL;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RTS_CONTROL_DISABLE:
Packit 1fb8d4
			/* do nothing since handflow is init-zeroed */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit Service 5a9772
			CommLog_Print(WLOG_WARN, "Unexpected fRtsControl value: %" PRIu32 "\n",
Packit 1fb8d4
			              lpDCB->fRtsControl);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fAbortOnError)
Packit 1fb8d4
	{
Packit 1fb8d4
		handflow.ControlHandShake |= SERIAL_ERROR_ABORT;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* lpDCB->fDummy2 not used */
Packit 1fb8d4
	/* lpLocalDcb->wReserved  ignored */
Packit 1fb8d4
	handflow.XonLimit = lpDCB->XonLim;
Packit 1fb8d4
	handflow.XoffLimit = lpDCB->XoffLim;
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow, sizeof(SERIAL_HANDFLOW),
Packit Service 5a9772
	                         NULL, 0, &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the handflow settings.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/** upcomingTermios stage **/
Packit 1fb8d4
	ZeroMemory(&upcomingTermios, sizeof(struct termios));
Packit 1fb8d4
Packit Service 5a9772
	if (tcgetattr(pComm->fd, &upcomingTermios) <
Packit 1fb8d4
	    0) /* NB: preserves current settings not directly handled by the Communication Functions */
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_IO_DEVICE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fBinary)
Packit 1fb8d4
	{
Packit 1fb8d4
		upcomingTermios.c_lflag &= ~ICANON;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		upcomingTermios.c_lflag |= ICANON;
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "Unexpected nonbinary mode, consider to unset the ICANON flag.");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDCB->fParity)
Packit 1fb8d4
	{
Packit 1fb8d4
		upcomingTermios.c_iflag |= INPCK;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		upcomingTermios.c_iflag &= ~INPCK;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * The SetCommState function reconfigures the communications
Packit 1fb8d4
	 * resource, but it does not affect the internal output and
Packit 1fb8d4
	 * input buffers of the specified driver. The buffers are not
Packit 1fb8d4
	 * flushed, and pending read and write operations are not
Packit 1fb8d4
	 * terminated prematurely.
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * TCSANOW matches the best this definition
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_IO_DEVICE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_INVALID_HANDLE
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	DWORD bytesReturned;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* as of today, SERIAL_TIMEOUTS and COMMTIMEOUTS structures are identical */
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, lpCommTimeouts,
Packit Service 5a9772
	                         sizeof(COMMTIMEOUTS), &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "GetCommTimeouts failure.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_INVALID_HANDLE
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	DWORD bytesReturned;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* as of today, SERIAL_TIMEOUTS and COMMTIMEOUTS structures are identical */
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_TIMEOUTS, lpCommTimeouts, sizeof(COMMTIMEOUTS),
Packit Service 5a9772
	                         NULL, 0, &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "SetCommTimeouts failure.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL GetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL GetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL SetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL SetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL SetCommBreak(HANDLE hFile)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL ClearCommBreak(HANDLE hFile)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL PurgeComm(HANDLE hFile, DWORD dwFlags)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	DWORD bytesReturned = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_PURGE, &dwFlags, sizeof(DWORD), NULL, 0,
Packit Service 5a9772
	                         &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "PurgeComm failure.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
	SERIAL_QUEUE_SIZE queueSize;
Packit 1fb8d4
	DWORD bytesReturned = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	queueSize.InSize = dwInQueue;
Packit 1fb8d4
	queueSize.OutSize = dwOutQueue;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_QUEUE_SIZE, &queueSize,
Packit 1fb8d4
	                         sizeof(SERIAL_QUEUE_SIZE), NULL, 0, &bytesReturned, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "SetCommTimeouts failure.");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL TransmitCommChar(HANDLE hFile, char cChar)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_COMM* pComm = (WINPR_COMM*)hFile;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: not implemented */
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CommLog_Print(WLOG_ERROR, "%s: Not implemented", __FUNCTION__);
Packit 1fb8d4
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Returns TRUE on success, FALSE otherwise. To get extended error
Packit 1fb8d4
 * information, call GetLastError.
Packit 1fb8d4
 *
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_DLL_INIT_FAILED
Packit 1fb8d4
 *   ERROR_OUTOFMEMORY was not possible to get mappings.
Packit 1fb8d4
 *   ERROR_INVALID_DATA was not possible to add the device.
Packit 1fb8d4
 */
Packit Service 5a9772
BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath)
Packit 1fb8d4
{
Packit 1fb8d4
	int i = 0;
Packit 1fb8d4
	LPTSTR storedDeviceName = NULL;
Packit 1fb8d4
	LPTSTR storedTargetPath = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&_CommDevicesLock);
Packit 1fb8d4
Packit 1fb8d4
	if (_CommDevices == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_DLL_INIT_FAILED);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	storedDeviceName = _tcsdup(lpDeviceName);
Packit 1fb8d4
Packit 1fb8d4
	if (storedDeviceName == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_OUTOFMEMORY);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	storedTargetPath = _tcsdup(lpTargetPath);
Packit 1fb8d4
Packit 1fb8d4
	if (storedTargetPath == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_OUTOFMEMORY);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < COMM_DEVICE_MAX; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (_CommDevices[i] != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (_tcscmp(_CommDevices[i]->name, storedDeviceName) == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* take over the emplacement */
Packit 1fb8d4
				free(_CommDevices[i]->name);
Packit 1fb8d4
				free(_CommDevices[i]->path);
Packit 1fb8d4
				_CommDevices[i]->name = storedDeviceName;
Packit 1fb8d4
				_CommDevices[i]->path = storedTargetPath;
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			/* new emplacement */
Packit 1fb8d4
			_CommDevices[i] = (COMM_DEVICE*)calloc(1, sizeof(COMM_DEVICE));
Packit 1fb8d4
Packit 1fb8d4
			if (_CommDevices[i] == NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_OUTOFMEMORY);
Packit 1fb8d4
				goto error_handle;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			_CommDevices[i]->name = storedDeviceName;
Packit 1fb8d4
			_CommDevices[i]->path = storedTargetPath;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (i == COMM_DEVICE_MAX)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_OUTOFMEMORY);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&_CommDevicesLock);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
error_handle:
Packit 1fb8d4
	free(storedDeviceName);
Packit 1fb8d4
	free(storedTargetPath);
Packit 1fb8d4
	LeaveCriticalSection(&_CommDevicesLock);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Returns the number of target paths in the buffer pointed to by
Packit 1fb8d4
 * lpTargetPath.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The current implementation returns in any case 0 and 1 target
Packit 1fb8d4
 * path. A NULL lpDeviceName is not supported yet to get all the
Packit 1fb8d4
 * paths.
Packit 1fb8d4
 *
Packit 1fb8d4
 * ERRORS:
Packit 1fb8d4
 *   ERROR_SUCCESS
Packit 1fb8d4
 *   ERROR_DLL_INIT_FAILED
Packit 1fb8d4
 *   ERROR_OUTOFMEMORY was not possible to get mappings.
Packit 1fb8d4
 *   ERROR_NOT_SUPPORTED equivalent QueryDosDevice feature not supported.
Packit 1fb8d4
 *   ERROR_INVALID_DATA was not possible to retrieve any device information.
Packit 1fb8d4
 *   ERROR_INSUFFICIENT_BUFFER too small lpTargetPath
Packit 1fb8d4
 */
Packit 1fb8d4
DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	LPTSTR storedTargetPath;
Packit 1fb8d4
	SetLastError(ERROR_SUCCESS);
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	if (_CommDevices == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_DLL_INIT_FAILED);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (lpDeviceName == NULL || lpTargetPath == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_NOT_SUPPORTED);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&_CommDevicesLock);
Packit 1fb8d4
	storedTargetPath = NULL;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < COMM_DEVICE_MAX; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (_CommDevices[i] != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (_tcscmp(_CommDevices[i]->name, lpDeviceName) == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				storedTargetPath = _CommDevices[i]->path;
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&_CommDevicesLock);
Packit 1fb8d4
Packit 1fb8d4
	if (storedTargetPath == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_DATA);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (_tcslen(storedTargetPath) + 2 > ucchMax)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INSUFFICIENT_BUFFER);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	_tcscpy(lpTargetPath, storedTargetPath);
Packit 1fb8d4
	lpTargetPath[_tcslen(storedTargetPath) + 1] = '\0'; /* 2nd final '\0' */
Packit 1fb8d4
	return _tcslen(lpTargetPath) + 2;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Checks whether lpDeviceName is a valid and registered Communication device.
Packit 1fb8d4
 */
Packit 1fb8d4
BOOL IsCommDevice(LPCTSTR lpDeviceName)
Packit 1fb8d4
{
Packit 1fb8d4
	TCHAR lpTargetPath[MAX_PATH];
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Sets
Packit 1fb8d4
 */
Packit 1fb8d4
void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID driverId)
Packit 1fb8d4
{
Packit 1fb8d4
	ULONG Type;
Packit 1fb8d4
	WINPR_HANDLE* Object;
Packit 1fb8d4
	WINPR_COMM* pComm;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Handle_GetInfo(hComm, &Type, &Object))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "_comm_setServerSerialDriver failure");
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pComm = (WINPR_COMM*)Object;
Packit 1fb8d4
	pComm->serverSerialDriverId = driverId;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static HANDLE_OPS ops = { CommIsHandled, CommCloseHandle,
Packit Service 5a9772
	                      CommGetFd,     NULL, /* CleanupHandle */
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL,
Packit Service 5a9772
	                      NULL,          NULL };
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363198%28v=vs.85%29.aspx
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param lpDeviceName e.g. COM1, \\.\COM1, ...
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param dwDesiredAccess expects GENERIC_READ | GENERIC_WRITE, a
Packit 1fb8d4
 * warning message is printed otherwise. TODO: better support.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param dwShareMode must be zero, INVALID_HANDLE_VALUE is returned
Packit 1fb8d4
 * otherwise and GetLastError() should return ERROR_SHARING_VIOLATION.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param lpSecurityAttributes NULL expected, a warning message is printed
Packit 1fb8d4
 * otherwise. TODO: better support.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param dwCreationDisposition must be OPEN_EXISTING. If the
Packit 1fb8d4
 * communication device doesn't exist INVALID_HANDLE_VALUE is returned
Packit 1fb8d4
 * and GetLastError() returns ERROR_FILE_NOT_FOUND.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param dwFlagsAndAttributes zero expected, a warning message is
Packit 1fb8d4
 * printed otherwise.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @param hTemplateFile must be NULL.
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return INVALID_HANDLE_VALUE on error.
Packit 1fb8d4
 */
Packit Service 5a9772
HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode,
Packit Service 5a9772
                       LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
Packit Service 5a9772
                       DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
Packit 1fb8d4
{
Packit 1fb8d4
	CHAR devicePath[MAX_PATH];
Packit 1fb8d4
	struct stat deviceStat;
Packit 1fb8d4
	WINPR_COMM* pComm = NULL;
Packit 1fb8d4
	struct termios upcomingTermios;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
Packit 1fb8d4
	if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE))
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "unexpected access to the device: 0x%08" PRIX32 "",
Packit 1fb8d4
		              dwDesiredAccess);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (dwShareMode != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_SHARING_VIOLATION);
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* TODO: Prevents other processes from opening a file or
Packit 1fb8d4
	 * device if they request delete, read, or write access. */
Packit 1fb8d4
Packit 1fb8d4
	if (lpSecurityAttributes != NULL)
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "unexpected security attributes, nLength=%" PRIu32 "",
Packit 1fb8d4
		              lpSecurityAttributes->nLength);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (dwCreationDisposition != OPEN_EXISTING)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_FILE_NOT_FOUND); /* FIXME: ERROR_NOT_SUPPORTED better? */
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* SetLastError(GetLastError()); */
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (stat(devicePath, &deviceStat) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "device not found %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_FILE_NOT_FOUND);
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!S_ISCHR(deviceStat.st_mode))
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "bad device %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_BAD_DEVICE);
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (dwFlagsAndAttributes != 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "unexpected flags and attributes: 0x%08" PRIX32 "",
Packit 1fb8d4
		              dwFlagsAndAttributes);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (hTemplateFile != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_NOT_SUPPORTED); /* FIXME: other proper error? */
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	pComm = (WINPR_COMM*)calloc(1, sizeof(WINPR_COMM));
Packit 1fb8d4
Packit 1fb8d4
	if (pComm == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_OUTOFMEMORY);
Packit 1fb8d4
		return INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WINPR_HANDLE_SET_TYPE_AND_MODE(pComm, HANDLE_TYPE_COMM, WINPR_FD_READ);
Packit 1fb8d4
	pComm->ops = &ops;
Packit 1fb8d4
	/* error_handle */
Packit 1fb8d4
	pComm->fd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "failed to open device %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_BAD_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_read < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "failed to open fd_read, device: %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_BAD_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	pComm->fd_read_event = eventfd(
Packit Service 5a9772
	    0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_read_event < 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "failed to open fd_read_event, device: %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_BAD_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	InitializeCriticalSection(&pComm->ReadLock);
Packit 1fb8d4
	pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_write < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "failed to open fd_write, device: %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_BAD_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	pComm->fd_write_event = eventfd(
Packit Service 5a9772
	    0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_write_event < 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		CommLog_Print(WLOG_WARN, "failed to open fd_write_event, device: %s", devicePath);
Packit 1fb8d4
		SetLastError(ERROR_BAD_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	InitializeCriticalSection(&pComm->WriteLock);
Packit 1fb8d4
	/* can also be setup later on with _comm_setServerSerialDriver() */
Packit 1fb8d4
	pComm->serverSerialDriverId = SerialDriverUnknown;
Packit 1fb8d4
	InitializeCriticalSection(&pComm->EventsLock);
Packit 1fb8d4
Packit 1fb8d4
	if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s.", errno,
Packit 1fb8d4
		              strerror(errno));
Packit 1fb8d4
		CommLog_Print(WLOG_WARN, "could not read counters.");
Packit 1fb8d4
		/* could not initialize counters but keep on.
Packit 1fb8d4
		 *
Packit 1fb8d4
		 * Not all drivers, especially for USB to serial
Packit 1fb8d4
		 * adapters (e.g. those based on pl2303), does support
Packit 1fb8d4
		 * this call.
Packit 1fb8d4
		 */
Packit 1fb8d4
		ZeroMemory(&(pComm->counters), sizeof(struct serial_icounter_struct));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* The binary/raw mode is required for the redirection but
Packit 1fb8d4
	 * only flags that are not handle somewhere-else, except
Packit 1fb8d4
	 * ICANON, are forced here. */
Packit 1fb8d4
	ZeroMemory(&upcomingTermios, sizeof(struct termios));
Packit 1fb8d4
Packit 1fb8d4
	if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_IO_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	upcomingTermios.c_iflag &=
Packit Service 5a9772
	    ~(/*IGNBRK |*/ BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL /*| IXON*/);
Packit 1fb8d4
	upcomingTermios.c_oflag = 0; /* <=> &= ~OPOST */
Packit Service 5a9772
	upcomingTermios.c_lflag = 0; /* <=> &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); */
Packit 1fb8d4
	/* upcomingTermios.c_cflag &= ~(CSIZE | PARENB); */
Packit 1fb8d4
	/* upcomingTermios.c_cflag |= CS8; */
Packit 1fb8d4
	/* About missing flags recommended by termios(3):
Packit 1fb8d4
	 *
Packit 1fb8d4
	 *   IGNBRK and IXON, see: IOCTL_SERIAL_SET_HANDFLOW
Packit 1fb8d4
	 *   CSIZE, PARENB and CS8, see: IOCTL_SERIAL_SET_LINE_CONTROL
Packit 1fb8d4
	 */
Packit 1fb8d4
	/* a few more settings required for the redirection */
Packit 1fb8d4
	upcomingTermios.c_cflag |= CLOCAL | CREAD;
Packit 1fb8d4
Packit 1fb8d4
	if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_IO_DEVICE);
Packit 1fb8d4
		goto error_handle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (HANDLE)pComm;
Packit 1fb8d4
error_handle:
Packit 1fb8d4
	CloseHandle(pComm);
Packit 1fb8d4
	return INVALID_HANDLE_VALUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL CommIsHandled(HANDLE handle)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_COMM* pComm;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pComm = (WINPR_COMM*)handle;
Packit 1fb8d4
Packit Service 5a9772
	if (!pComm || (pComm->Type != HANDLE_TYPE_COMM) || (pComm == INVALID_HANDLE_VALUE))
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL CommCloseHandle(HANDLE handle)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_COMM* pComm;
Packit 1fb8d4
Packit 1fb8d4
	if (!CommInitialized())
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pComm = (WINPR_COMM*)handle;
Packit 1fb8d4
Packit 1fb8d4
	if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetLastError(ERROR_INVALID_HANDLE);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING)
Packit 1fb8d4
	{
Packit 1fb8d4
		ULONG WaitMask = 0;
Packit 1fb8d4
		DWORD BytesReturned = 0;
Packit 1fb8d4
Packit 1fb8d4
		/* ensures to gracefully stop the WAIT_ON_MASK's loop */
Packit Service 5a9772
		if (!CommDeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK, &WaitMask, sizeof(ULONG), NULL,
Packit Service 5a9772
		                         0, &BytesReturned, NULL))
Packit 1fb8d4
		{
Packit 1fb8d4
			CommLog_Print(WLOG_WARN, "failure to WAIT_ON_MASK's loop!");
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	DeleteCriticalSection(&pComm->ReadLock);
Packit 1fb8d4
	DeleteCriticalSection(&pComm->WriteLock);
Packit 1fb8d4
	DeleteCriticalSection(&pComm->EventsLock);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd > 0)
Packit 1fb8d4
		close(pComm->fd);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_write > 0)
Packit 1fb8d4
		close(pComm->fd_write);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_write_event > 0)
Packit 1fb8d4
		close(pComm->fd_write_event);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_read > 0)
Packit 1fb8d4
		close(pComm->fd_read);
Packit 1fb8d4
Packit 1fb8d4
	if (pComm->fd_read_event > 0)
Packit 1fb8d4
		close(pComm->fd_read_event);
Packit 1fb8d4
Packit 1fb8d4
	free(pComm);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifndef WITH_EVENTFD_READ_WRITE
Packit 1fb8d4
int eventfd_read(int fd, eventfd_t* value)
Packit 1fb8d4
{
Packit 1fb8d4
	return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int eventfd_write(int fd, eventfd_t value)
Packit 1fb8d4
{
Packit 1fb8d4
	return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
Packit 1fb8d4
}
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#endif /* __linux__ */