Blame winpr/libwinpr/comm/comm.c

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