Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
49
third_party/FreeRDP/winpr/libwinpr/comm/CMakeLists.txt
vendored
Normal file
49
third_party/FreeRDP/winpr/libwinpr/comm/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-comm cmake build script
|
||||
#
|
||||
# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(MODULE_NAME "winpr-comm")
|
||||
set(MODULE_PREFIX "WINPR_COMM")
|
||||
|
||||
if(NOT WIN32)
|
||||
set(${MODULE_PREFIX}_SRCS comm.c comm.h)
|
||||
if(NOT EMSCRIPTEN AND NOT APPLE)
|
||||
winpr_definition_add(WINPR_HAVE_SERIAL_SUPPORT)
|
||||
list(
|
||||
APPEND
|
||||
${MODULE_PREFIX}_SRCS
|
||||
comm_io.c
|
||||
comm_ioctl.c
|
||||
comm_ioctl.h
|
||||
comm_serial_sys.c
|
||||
comm_serial_sys.h
|
||||
comm_sercx_sys.c
|
||||
comm_sercx_sys.h
|
||||
comm_sercx2_sys.c
|
||||
comm_sercx2_sys.h
|
||||
)
|
||||
else()
|
||||
list(APPEND ${MODULE_PREFIX}_SRCS comm_ioctl_dummy.c comm_ioctl.h)
|
||||
endif()
|
||||
|
||||
winpr_module_add(${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
if(NOT EMSCRIPTEN)
|
||||
if(BUILD_TESTING_INTERNAL AND BUILD_COMM_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
9
third_party/FreeRDP/winpr/libwinpr/comm/ModuleOptions.cmake
vendored
Normal file
9
third_party/FreeRDP/winpr/libwinpr/comm/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
set(MINWIN_LAYER "1")
|
||||
set(MINWIN_GROUP "core")
|
||||
set(MINWIN_MAJOR_VERSION "1")
|
||||
set(MINWIN_MINOR_VERSION "0")
|
||||
set(MINWIN_SHORT_NAME "comm")
|
||||
set(MINWIN_LONG_NAME "Serial Communication API")
|
||||
set(MODULE_LIBRARY_NAME
|
||||
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
|
||||
)
|
||||
1920
third_party/FreeRDP/winpr/libwinpr/comm/comm.c
vendored
Normal file
1920
third_party/FreeRDP/winpr/libwinpr/comm/comm.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
134
third_party/FreeRDP/winpr/libwinpr/comm/comm.h
vendored
Normal file
134
third_party/FreeRDP/winpr/libwinpr/comm/comm.h
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_COMM_PRIVATE_H
|
||||
#define WINPR_COMM_PRIVATE_H
|
||||
|
||||
#if defined(__linux__)
|
||||
#define WINPR_HAVE_COMM_COUNTERS
|
||||
#include <linux/serial.h>
|
||||
#endif
|
||||
|
||||
#include <winpr/comm.h>
|
||||
|
||||
#include "../handle/handle.h"
|
||||
#include <winpr/config.h>
|
||||
|
||||
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
struct winpr_comm
|
||||
{
|
||||
WINPR_HANDLE common;
|
||||
|
||||
int fd;
|
||||
|
||||
int fd_read;
|
||||
int fd_read_event; /* as of today, only used by _purge() */
|
||||
CRITICAL_SECTION ReadLock;
|
||||
|
||||
int fd_write;
|
||||
int fd_write_event; /* as of today, only used by _purge() */
|
||||
CRITICAL_SECTION WriteLock;
|
||||
|
||||
/* permissive mode on errors. If TRUE (default is FALSE)
|
||||
* CommDeviceIoControl always return TRUE.
|
||||
*
|
||||
* Not all features are supported yet and an error is then returned when
|
||||
* an application turns them on (e.g: i/o buffers > 4096). It appeared
|
||||
* though that devices and applications can be still functional on such
|
||||
* errors.
|
||||
*
|
||||
* see also: comm_ioctl.c
|
||||
*
|
||||
* FIXME: getting rid of this flag once all features supported.
|
||||
*/
|
||||
BOOL permissive;
|
||||
|
||||
SERIAL_DRIVER_ID serverSerialDriverId;
|
||||
|
||||
COMMTIMEOUTS timeouts;
|
||||
|
||||
CRITICAL_SECTION
|
||||
EventsLock; /* protects counters, WaitEventMask and PendingEvents */
|
||||
#if defined(WINPR_HAVE_COMM_COUNTERS)
|
||||
struct serial_icounter_struct counters;
|
||||
#endif
|
||||
ULONG WaitEventMask;
|
||||
ULONG PendingEvents;
|
||||
|
||||
BYTE eventChar;
|
||||
/* NB: CloseHandle() has to free resources */
|
||||
ULONG XOnLimit;
|
||||
ULONG XOffLimit;
|
||||
|
||||
#if defined(WINPR_HAVE_COMM_COUNTERS)
|
||||
BOOL TIOCGICOUNTSupported;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct winpr_comm WINPR_COMM;
|
||||
|
||||
#define SERIAL_EV_RXCHAR 0x0001
|
||||
#define SERIAL_EV_RXFLAG 0x0002
|
||||
#define SERIAL_EV_TXEMPTY 0x0004
|
||||
#define SERIAL_EV_CTS 0x0008
|
||||
#define SERIAL_EV_DSR 0x0010
|
||||
#define SERIAL_EV_RLSD 0x0020
|
||||
#define SERIAL_EV_BREAK 0x0040
|
||||
#define SERIAL_EV_ERR 0x0080
|
||||
#define SERIAL_EV_RING 0x0100
|
||||
#define SERIAL_EV_PERR 0x0200
|
||||
#define SERIAL_EV_RX80FULL 0x0400
|
||||
#define SERIAL_EV_EVENT1 0x0800
|
||||
#define SERIAL_EV_EVENT2 0x1000
|
||||
#define SERIAL_EV_WINPR_WAITING 0x4000 /* bit today unused by other SERIAL_EV_* */
|
||||
#define SERIAL_EV_WINPR_STOP 0x8000 /* bit today unused by other SERIAL_EV_* */
|
||||
|
||||
#define WINPR_PURGE_TXABORT 0x00000001 /* abort pending transmission */
|
||||
#define WINPR_PURGE_RXABORT 0x00000002 /* abort pending reception */
|
||||
|
||||
#define CommLog_Print(level, ...) CommLog_PrintEx(level, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
WINPR_ATTR_FORMAT_ARG(5, 6)
|
||||
void CommLog_PrintEx(DWORD level, const char* file, size_t line, const char* fkt,
|
||||
WINPR_FORMAT_ARG const char* fmt, ...);
|
||||
|
||||
BOOL CommIsHandled(HANDLE handle);
|
||||
BOOL CommIsHandleValid(HANDLE handle);
|
||||
BOOL CommCloseHandle(HANDLE handle);
|
||||
const HANDLE_CREATOR* GetCommHandleCreator(void);
|
||||
|
||||
#define CommIoCtl(pComm, ctl, data) \
|
||||
CommIoCtl_int((pComm), (ctl), (data), __FILE__, __func__, __LINE__)
|
||||
BOOL CommIoCtl_int(WINPR_COMM* pComm, unsigned long int ctl, void* data, const char* file,
|
||||
const char* fkt, size_t line);
|
||||
BOOL CommUpdateIOCount(HANDLE handle, BOOL checkSupportStatus);
|
||||
|
||||
const char* CommSerialEvString(ULONG status, char* buffer, size_t size);
|
||||
|
||||
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
|
||||
#ifndef WITH_EVENTFD_READ_WRITE
|
||||
int eventfd_read(int fd, eventfd_t* value);
|
||||
int eventfd_write(int fd, eventfd_t value);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_COMM_PRIVATE_H */
|
||||
567
third_party/FreeRDP/winpr/libwinpr/comm/comm_io.c
vendored
Normal file
567
third_party/FreeRDP/winpr/libwinpr/comm/comm_io.c
vendored
Normal file
@@ -0,0 +1,567 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <winpr/io.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include "comm.h"
|
||||
|
||||
BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
|
||||
{
|
||||
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
|
||||
|
||||
if (!CommIsHandled(hDevice))
|
||||
return FALSE;
|
||||
|
||||
pComm->permissive = permissive;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Computes VTIME in deciseconds from Ti in milliseconds */
|
||||
static UCHAR svtime(ULONG Ti)
|
||||
{
|
||||
/* FIXME: look for an equivalent math function otherwise let
|
||||
* do the compiler do the optimization */
|
||||
if (Ti == 0)
|
||||
return 0;
|
||||
else if (Ti < 100)
|
||||
return 1;
|
||||
else if (Ti > 25500)
|
||||
return 255; /* 0xFF */
|
||||
else
|
||||
return (UCHAR)(Ti / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* ERRORS:
|
||||
* ERROR_INVALID_HANDLE
|
||||
* ERROR_NOT_SUPPORTED
|
||||
* ERROR_INVALID_PARAMETER
|
||||
* ERROR_TIMEOUT
|
||||
* ERROR_IO_DEVICE
|
||||
* ERROR_BAD_DEVICE
|
||||
*/
|
||||
BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
|
||||
int biggestFd = -1;
|
||||
fd_set read_set;
|
||||
int nbFds = 0;
|
||||
COMMTIMEOUTS* pTimeouts = nullptr;
|
||||
UCHAR vmin = 0;
|
||||
UCHAR vtime = 0;
|
||||
LONGLONG Tmax = 0;
|
||||
struct timeval tmaxTimeout;
|
||||
struct timeval* pTmaxTimeout = nullptr;
|
||||
struct termios currentTermios;
|
||||
EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */
|
||||
|
||||
if (!CommIsHandled(hDevice))
|
||||
goto return_false;
|
||||
|
||||
if (lpOverlapped != nullptr)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
if (lpNumberOfBytesRead == nullptr)
|
||||
{
|
||||
SetLastError(
|
||||
ERROR_INVALID_PARAMETER); /* since we doesn't support lpOverlapped != nullptr */
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesRead = 0; /* will be adjusted if required ... */
|
||||
|
||||
if (nNumberOfBytesToRead <= 0) /* N */
|
||||
{
|
||||
goto return_true; /* FIXME: or FALSE? */
|
||||
}
|
||||
|
||||
if (tcgetattr(pComm->fd, ¤tTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
if (currentTermios.c_lflag & ICANON)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN, "Canonical mode not supported"); /* the timeout could not be set */
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx
|
||||
*
|
||||
* ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME |
|
||||
* TMAX | 0 | 0 | 0 | N | 0 |
|
||||
* INDEF | Blocks for N bytes available. 0< Ti <MAXULONG | 0 | 0 |
|
||||
* N | Ti | INDEF | Blocks on first byte, then use Ti between bytes. MAXULONG | 0 | 0
|
||||
* | 0 | 0 | 0 | Returns immediately with bytes available (don't block) MAXULONG |
|
||||
* MAXULONG | 0< Tc <MAXULONG | N | 0 | Tc | Blocks on first byte
|
||||
* during Tc or returns immediately with bytes available MAXULONG | m |
|
||||
* MAXULONG | | Invalid 0 | m | 0< Tc
|
||||
* <MAXULONG | N | 0 | Tmax | Blocks on first byte during Tmax or returns
|
||||
* immediately with bytes available 0< Ti <MAXULONG | m | 0<
|
||||
* Tc <MAXULONG | N | Ti | Tmax | Blocks on first byte, then use Ti between bytes.
|
||||
* Tmax is used for the whole system call.
|
||||
*/
|
||||
/* NB: timeouts are in milliseconds, VTIME are in deciseconds and is an unsigned char */
|
||||
/* FIXME: double check whether open(pComm->fd_read_event, O_NONBLOCK) doesn't conflict with
|
||||
* above use cases */
|
||||
pTimeouts = &(pComm->timeouts);
|
||||
|
||||
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
|
||||
(pTimeouts->ReadTotalTimeoutConstant == MAXULONG))
|
||||
{
|
||||
CommLog_Print(
|
||||
WLOG_WARN,
|
||||
"ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
/* VMIN */
|
||||
|
||||
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
|
||||
(pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0))
|
||||
{
|
||||
vmin = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* N */
|
||||
/* vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255;*/ /* 0xFF */
|
||||
/* NB: we might wait endlessly with vmin=N, prefer to
|
||||
* force vmin=1 and return with bytes
|
||||
* available. FIXME: is a feature disarded here? */
|
||||
vmin = 1;
|
||||
}
|
||||
|
||||
/* VTIME */
|
||||
|
||||
if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG))
|
||||
{
|
||||
/* Ti */
|
||||
vtime = svtime(pTimeouts->ReadIntervalTimeout);
|
||||
}
|
||||
|
||||
/* TMAX */
|
||||
pTmaxTimeout = &tmaxTimeout;
|
||||
|
||||
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
|
||||
(pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG))
|
||||
{
|
||||
/* Tc */
|
||||
Tmax = pTimeouts->ReadTotalTimeoutConstant;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Tmax */
|
||||
Tmax = 1ll * nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier +
|
||||
1ll * pTimeouts->ReadTotalTimeoutConstant;
|
||||
|
||||
/* INDEFinitely */
|
||||
if ((Tmax == 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG) &&
|
||||
(pTimeouts->ReadTotalTimeoutMultiplier == 0))
|
||||
pTmaxTimeout = nullptr;
|
||||
}
|
||||
|
||||
if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime))
|
||||
{
|
||||
currentTermios.c_cc[VMIN] = vmin;
|
||||
currentTermios.c_cc[VTIME] = vtime;
|
||||
|
||||
if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"CommReadFile failure, could not apply new timeout values: VMIN=%" PRIu8
|
||||
", VTIME=%" PRIu8 "",
|
||||
vmin, vtime);
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
goto return_false;
|
||||
}
|
||||
}
|
||||
|
||||
/* wait indefinitely if pTmaxTimeout is nullptr */
|
||||
|
||||
if (pTmaxTimeout != nullptr)
|
||||
{
|
||||
ZeroMemory(pTmaxTimeout, sizeof(struct timeval));
|
||||
|
||||
if (Tmax > 0) /* return immdiately if Tmax == 0 */
|
||||
{
|
||||
pTmaxTimeout->tv_sec = Tmax / 1000; /* s */
|
||||
pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000; /* us */
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: had expected eventfd_write() to return EAGAIN when
|
||||
* there is no eventfd_read() but this not the case. */
|
||||
/* discard a possible and no more relevant event */
|
||||
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
|
||||
{
|
||||
eventfd_t val = 0;
|
||||
(void)eventfd_read(pComm->fd_read_event, &val);
|
||||
}
|
||||
#endif
|
||||
biggestFd = pComm->fd_read;
|
||||
|
||||
if (pComm->fd_read_event > biggestFd)
|
||||
biggestFd = pComm->fd_read_event;
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
WINPR_ASSERT(pComm->fd_read_event < FD_SETSIZE);
|
||||
WINPR_ASSERT(pComm->fd_read < FD_SETSIZE);
|
||||
FD_SET(pComm->fd_read_event, &read_set);
|
||||
FD_SET(pComm->fd_read, &read_set);
|
||||
nbFds = select(biggestFd + 1, &read_set, nullptr, nullptr, pTmaxTimeout);
|
||||
|
||||
if (nbFds < 0)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
if (nbFds == 0)
|
||||
{
|
||||
/* timeout */
|
||||
SetLastError(ERROR_TIMEOUT);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
/* read_set */
|
||||
|
||||
if (FD_ISSET(pComm->fd_read_event, &read_set))
|
||||
{
|
||||
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
|
||||
eventfd_t event = 0;
|
||||
|
||||
if (eventfd_read(pComm->fd_read_event, &event) < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
WINPR_ASSERT(FALSE); /* not quite sure this should ever happen */
|
||||
/* keep on */
|
||||
}
|
||||
else
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"unexpected error on reading fd_read_event, errno=[%d] %s\n", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
/* FIXME: goto return_false ? */
|
||||
}
|
||||
|
||||
WINPR_ASSERT(errno == EAGAIN);
|
||||
}
|
||||
|
||||
if (event == WINPR_PURGE_RXABORT)
|
||||
{
|
||||
SetLastError(ERROR_CANCELLED);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(event == WINPR_PURGE_RXABORT); /* no other expected event so far */
|
||||
#endif
|
||||
}
|
||||
|
||||
if (FD_ISSET(pComm->fd_read, &read_set))
|
||||
{
|
||||
ssize_t nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead);
|
||||
|
||||
if ((nbRead < 0) || (nbRead > nNumberOfBytesToRead))
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"CommReadFile failed, ReadIntervalTimeout=%" PRIu32
|
||||
", ReadTotalTimeoutMultiplier=%" PRIu32
|
||||
", ReadTotalTimeoutConstant=%" PRIu32 " VMIN=%u, VTIME=%u",
|
||||
pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier,
|
||||
pTimeouts->ReadTotalTimeoutConstant, currentTermios.c_cc[VMIN],
|
||||
currentTermios.c_cc[VTIME]);
|
||||
CommLog_Print(
|
||||
WLOG_WARN, "CommReadFile failed, nNumberOfBytesToRead=%" PRIu32 ", errno=[%d] %s",
|
||||
nNumberOfBytesToRead, errno, winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
/* keep on */
|
||||
goto return_true; /* expect a read-loop to be implemented on the server side */
|
||||
}
|
||||
else if (errno == EBADF)
|
||||
{
|
||||
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
|
||||
goto return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPR_ASSERT(FALSE);
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
goto return_false;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbRead == 0)
|
||||
{
|
||||
/* termios timeout */
|
||||
SetLastError(ERROR_TIMEOUT);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesRead = WINPR_ASSERTING_INT_CAST(UINT32, nbRead);
|
||||
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
if (pComm->PendingEvents & SERIAL_EV_WINPR_WAITING)
|
||||
{
|
||||
if (pComm->eventChar != '\0' &&
|
||||
memchr(lpBuffer, pComm->eventChar, WINPR_ASSERTING_INT_CAST(size_t, nbRead)))
|
||||
pComm->PendingEvents |= SERIAL_EV_RXCHAR;
|
||||
}
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
goto return_true;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(FALSE);
|
||||
*lpNumberOfBytesRead = 0;
|
||||
return_false:
|
||||
LeaveCriticalSection(&pComm->ReadLock);
|
||||
return FALSE;
|
||||
return_true:
|
||||
LeaveCriticalSection(&pComm->ReadLock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ERRORS:
|
||||
* ERROR_INVALID_HANDLE
|
||||
* ERROR_NOT_SUPPORTED
|
||||
* ERROR_INVALID_PARAMETER
|
||||
* ERROR_BAD_DEVICE
|
||||
*/
|
||||
BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
|
||||
struct timeval tmaxTimeout;
|
||||
struct timeval* pTmaxTimeout = nullptr;
|
||||
EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */
|
||||
|
||||
if (!CommIsHandled(hDevice))
|
||||
goto return_false;
|
||||
|
||||
if (lpOverlapped != nullptr)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
if (lpNumberOfBytesWritten == nullptr)
|
||||
{
|
||||
SetLastError(
|
||||
ERROR_INVALID_PARAMETER); /* since we doesn't support lpOverlapped != nullptr */
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesWritten = 0; /* will be adjusted if required ... */
|
||||
|
||||
if (nNumberOfBytesToWrite <= 0)
|
||||
{
|
||||
goto return_true; /* FIXME: or FALSE? */
|
||||
}
|
||||
|
||||
/* FIXME: had expected eventfd_write() to return EAGAIN when
|
||||
* there is no eventfd_read() but this not the case. */
|
||||
/* discard a possible and no more relevant event */
|
||||
|
||||
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
|
||||
{
|
||||
eventfd_t val = 0;
|
||||
(void)eventfd_read(pComm->fd_write_event, &val);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
/* ms */
|
||||
const LONGLONG Tmax =
|
||||
1ll * nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier +
|
||||
1ll * pComm->timeouts.WriteTotalTimeoutConstant;
|
||||
/* NB: select() may update the timeout argument to indicate
|
||||
* how much time was left. Keep the timeout variable out of
|
||||
* the while() */
|
||||
pTmaxTimeout = &tmaxTimeout;
|
||||
ZeroMemory(pTmaxTimeout, sizeof(struct timeval));
|
||||
|
||||
if (Tmax > 0)
|
||||
{
|
||||
pTmaxTimeout->tv_sec = Tmax / 1000; /* s */
|
||||
pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000; /* us */
|
||||
}
|
||||
else if ((pComm->timeouts.WriteTotalTimeoutMultiplier == 0) &&
|
||||
(pComm->timeouts.WriteTotalTimeoutConstant == 0))
|
||||
{
|
||||
pTmaxTimeout = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* else return immdiately */
|
||||
|
||||
while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite)
|
||||
{
|
||||
int biggestFd = -1;
|
||||
fd_set event_set;
|
||||
fd_set write_set;
|
||||
int nbFds = 0;
|
||||
biggestFd = pComm->fd_write;
|
||||
|
||||
if (pComm->fd_write_event > biggestFd)
|
||||
biggestFd = pComm->fd_write_event;
|
||||
|
||||
FD_ZERO(&event_set);
|
||||
FD_ZERO(&write_set);
|
||||
WINPR_ASSERT(pComm->fd_write_event < FD_SETSIZE);
|
||||
WINPR_ASSERT(pComm->fd_write < FD_SETSIZE);
|
||||
FD_SET(pComm->fd_write_event, &event_set);
|
||||
FD_SET(pComm->fd_write, &write_set);
|
||||
nbFds = select(biggestFd + 1, &event_set, &write_set, nullptr, pTmaxTimeout);
|
||||
|
||||
if (nbFds < 0)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
if (nbFds == 0)
|
||||
{
|
||||
/* timeout */
|
||||
SetLastError(ERROR_TIMEOUT);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
/* event_set */
|
||||
|
||||
if (FD_ISSET(pComm->fd_write_event, &event_set))
|
||||
{
|
||||
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
|
||||
eventfd_t event = 0;
|
||||
|
||||
if (eventfd_read(pComm->fd_write_event, &event) < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
WINPR_ASSERT(FALSE); /* not quite sure this should ever happen */
|
||||
/* keep on */
|
||||
}
|
||||
else
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"unexpected error on reading fd_write_event, errno=[%d] %s\n",
|
||||
errno, winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
/* FIXME: goto return_false ? */
|
||||
}
|
||||
|
||||
WINPR_ASSERT(errno == EAGAIN);
|
||||
}
|
||||
|
||||
if (event == WINPR_PURGE_TXABORT)
|
||||
{
|
||||
SetLastError(ERROR_CANCELLED);
|
||||
goto return_false;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(event == WINPR_PURGE_TXABORT); /* no other expected event so far */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* write_set */
|
||||
|
||||
if (FD_ISSET(pComm->fd_write, &write_set))
|
||||
{
|
||||
ssize_t nbWritten = 0;
|
||||
const BYTE* ptr = lpBuffer;
|
||||
nbWritten = write(pComm->fd_write, &ptr[*lpNumberOfBytesWritten],
|
||||
nNumberOfBytesToWrite - (*lpNumberOfBytesWritten));
|
||||
|
||||
if (nbWritten < 0)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"CommWriteFile failed after %" PRIu32
|
||||
" bytes written, errno=[%d] %s\n",
|
||||
*lpNumberOfBytesWritten, errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
/* keep on */
|
||||
continue;
|
||||
}
|
||||
else if (errno == EBADF)
|
||||
{
|
||||
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
|
||||
goto return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPR_ASSERT(FALSE);
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
goto return_false;
|
||||
}
|
||||
}
|
||||
|
||||
*lpNumberOfBytesWritten += nbWritten;
|
||||
}
|
||||
} /* while */
|
||||
|
||||
/* FIXME: this call to tcdrain() doesn't look correct and
|
||||
* might hide a bug but was required while testing a serial
|
||||
* printer. Its driver was expecting the modem line status
|
||||
* SERIAL_MSR_DSR true after the sending which was never
|
||||
* happening otherwise. A purge was also done before each
|
||||
* Write operation. The serial port was opened with:
|
||||
* DesiredAccess=0x0012019F. The printer worked fine with
|
||||
* mstsc. */
|
||||
tcdrain(pComm->fd_write);
|
||||
|
||||
return_true:
|
||||
LeaveCriticalSection(&pComm->WriteLock);
|
||||
return TRUE;
|
||||
|
||||
return_false:
|
||||
LeaveCriticalSection(&pComm->WriteLock);
|
||||
return FALSE;
|
||||
}
|
||||
759
third_party/FreeRDP/winpr/libwinpr/comm/comm_ioctl.c
vendored
Normal file
759
third_party/FreeRDP/winpr/libwinpr/comm/comm_ioctl.c
vendored
Normal file
@@ -0,0 +1,759 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2011 O.S. Systems Software Ltda.
|
||||
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include "comm.h"
|
||||
#include "comm_ioctl.h"
|
||||
#include "comm_serial_sys.h"
|
||||
#include "comm_sercx_sys.h"
|
||||
#include "comm_sercx2_sys.h"
|
||||
|
||||
static const char* comm_ioctl_modem_status_string(ULONG status, char* buffer, size_t size);
|
||||
|
||||
/* NB: MS-RDPESP's recommendation:
|
||||
*
|
||||
* <2> Section 3.2.5.1.6: Windows Implementations use IOCTL constants
|
||||
* for IoControlCode values. The content and values of the IOCTLs are
|
||||
* opaque to the protocol. On the server side, the data contained in
|
||||
* an IOCTL is simply packaged and sent to the client side. For
|
||||
* maximum compatibility between the different versions of the Windows
|
||||
* operating system, the client implementation only singles out
|
||||
* critical IOCTLs and invokes the applicable Win32 port API. The
|
||||
* other IOCTLS are passed directly to the client-side driver, and the
|
||||
* processing of this value depends on the drivers installed on the
|
||||
* client side. The values and parameters for these IOCTLS can be
|
||||
* found in [MSFT-W2KDDK] Volume 2, Part 2—Serial and Parallel
|
||||
* Drivers, and in [MSDN-PORTS].
|
||||
*/
|
||||
static BOOL s_CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
char buffer[128] = WINPR_C_ARRAY_INIT;
|
||||
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
|
||||
const SERIAL_DRIVER* pServerSerialDriver = nullptr;
|
||||
|
||||
if (!CommIsHandleValid(hDevice))
|
||||
return FALSE;
|
||||
|
||||
if (lpOverlapped)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (lpBytesReturned == nullptr)
|
||||
{
|
||||
SetLastError(
|
||||
ERROR_INVALID_PARAMETER); /* since we doesn't support lpOverlapped != nullptr */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* clear any previous last error */
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
*lpBytesReturned = 0; /* will be adjusted if required ... */
|
||||
|
||||
CommLog_Print(WLOG_DEBUG, "CommDeviceIoControl: IoControlCode: %s [0x%08" PRIx32 "]",
|
||||
_comm_serial_ioctl_name(dwIoControlCode), dwIoControlCode);
|
||||
|
||||
/* remoteSerialDriver to be use ...
|
||||
*
|
||||
* FIXME: might prefer to use an automatic rather than static structure
|
||||
*/
|
||||
switch (pComm->serverSerialDriverId)
|
||||
{
|
||||
case SerialDriverSerialSys:
|
||||
pServerSerialDriver = SerialSys_s();
|
||||
break;
|
||||
|
||||
case SerialDriverSerCxSys:
|
||||
pServerSerialDriver = SerCxSys_s();
|
||||
break;
|
||||
|
||||
case SerialDriverSerCx2Sys:
|
||||
pServerSerialDriver = SerCx2Sys_s();
|
||||
break;
|
||||
|
||||
case SerialDriverUnknown:
|
||||
default:
|
||||
CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%u), using SerCx2.sys",
|
||||
pComm->serverSerialDriverId);
|
||||
pServerSerialDriver = SerCx2Sys_s();
|
||||
break;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(pServerSerialDriver != nullptr);
|
||||
|
||||
switch (dwIoControlCode)
|
||||
{
|
||||
case IOCTL_USBPRINT_GET_1284_ID:
|
||||
{
|
||||
/* FIXME:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */
|
||||
*lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_BAUD_RATE:
|
||||
{
|
||||
if (pServerSerialDriver->set_baud_rate)
|
||||
{
|
||||
SERIAL_BAUD_RATE* pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_BAUD_RATE));
|
||||
if (nInBufferSize < sizeof(SERIAL_BAUD_RATE))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_BAUD_RATE:
|
||||
{
|
||||
if (pServerSerialDriver->get_baud_rate)
|
||||
{
|
||||
SERIAL_BAUD_RATE* pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE));
|
||||
if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(SERIAL_BAUD_RATE);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_PROPERTIES:
|
||||
{
|
||||
if (pServerSerialDriver->get_properties)
|
||||
{
|
||||
COMMPROP* pProperties = (COMMPROP*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(COMMPROP));
|
||||
if (nOutBufferSize < sizeof(COMMPROP))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_properties(pComm, pProperties))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(COMMPROP);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_CHARS:
|
||||
{
|
||||
if (pServerSerialDriver->set_serial_chars)
|
||||
{
|
||||
SERIAL_CHARS* pSerialChars = (SERIAL_CHARS*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_CHARS));
|
||||
if (nInBufferSize < sizeof(SERIAL_CHARS))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_CHARS:
|
||||
{
|
||||
if (pServerSerialDriver->get_serial_chars)
|
||||
{
|
||||
SERIAL_CHARS* pSerialChars = (SERIAL_CHARS*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_CHARS));
|
||||
if (nOutBufferSize < sizeof(SERIAL_CHARS))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(SERIAL_CHARS);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_LINE_CONTROL:
|
||||
{
|
||||
if (pServerSerialDriver->set_line_control)
|
||||
{
|
||||
SERIAL_LINE_CONTROL* pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL));
|
||||
if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->set_line_control(pComm, pLineControl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_LINE_CONTROL:
|
||||
{
|
||||
if (pServerSerialDriver->get_line_control)
|
||||
{
|
||||
SERIAL_LINE_CONTROL* pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL));
|
||||
if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(SERIAL_LINE_CONTROL);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_HANDFLOW:
|
||||
{
|
||||
if (pServerSerialDriver->set_handflow)
|
||||
{
|
||||
SERIAL_HANDFLOW* pHandflow = (SERIAL_HANDFLOW*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_HANDFLOW));
|
||||
if (nInBufferSize < sizeof(SERIAL_HANDFLOW))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->set_handflow(pComm, pHandflow);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_HANDFLOW:
|
||||
{
|
||||
if (pServerSerialDriver->get_handflow)
|
||||
{
|
||||
SERIAL_HANDFLOW* pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_HANDFLOW));
|
||||
if (nOutBufferSize < sizeof(SERIAL_HANDFLOW))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(SERIAL_HANDFLOW);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_TIMEOUTS:
|
||||
{
|
||||
if (pServerSerialDriver->set_timeouts)
|
||||
{
|
||||
SERIAL_TIMEOUTS* pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_TIMEOUTS));
|
||||
if (nInBufferSize < sizeof(SERIAL_TIMEOUTS))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->set_timeouts(pComm, pHandflow);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_TIMEOUTS:
|
||||
{
|
||||
if (pServerSerialDriver->get_timeouts)
|
||||
{
|
||||
SERIAL_TIMEOUTS* pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS));
|
||||
if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(SERIAL_TIMEOUTS);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_DTR:
|
||||
{
|
||||
if (pServerSerialDriver->set_dtr)
|
||||
{
|
||||
return pServerSerialDriver->set_dtr(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_CLR_DTR:
|
||||
{
|
||||
if (pServerSerialDriver->clear_dtr)
|
||||
{
|
||||
return pServerSerialDriver->clear_dtr(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_RTS:
|
||||
{
|
||||
if (pServerSerialDriver->set_rts)
|
||||
{
|
||||
return pServerSerialDriver->set_rts(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_CLR_RTS:
|
||||
{
|
||||
if (pServerSerialDriver->clear_rts)
|
||||
{
|
||||
return pServerSerialDriver->clear_rts(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_MODEMSTATUS:
|
||||
{
|
||||
if (pServerSerialDriver->get_modemstatus)
|
||||
{
|
||||
ULONG* pRegister = (ULONG*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
|
||||
if (nOutBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
|
||||
return FALSE;
|
||||
|
||||
CommLog_Print(WLOG_DEBUG, "modem status %s" PRIx32,
|
||||
comm_ioctl_modem_status_string(*pRegister, buffer, sizeof(buffer)));
|
||||
*lpBytesReturned = sizeof(ULONG);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_WAIT_MASK:
|
||||
{
|
||||
if (pServerSerialDriver->set_wait_mask)
|
||||
{
|
||||
ULONG* pWaitMask = (ULONG*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(ULONG));
|
||||
if (nInBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const BOOL rc = pServerSerialDriver->set_wait_mask(pComm, pWaitMask);
|
||||
CommLog_Print(WLOG_DEBUG, "set_wait_mask %s -> %d",
|
||||
CommSerialEvString(*pWaitMask, buffer, sizeof(buffer)), rc);
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_WAIT_MASK:
|
||||
{
|
||||
if (pServerSerialDriver->get_wait_mask)
|
||||
{
|
||||
ULONG* pWaitMask = (ULONG*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
|
||||
if (nOutBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
|
||||
return FALSE;
|
||||
|
||||
CommLog_Print(WLOG_DEBUG, "get_wait_mask %s",
|
||||
CommSerialEvString(*pWaitMask, buffer, sizeof(buffer)));
|
||||
*lpBytesReturned = sizeof(ULONG);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_WAIT_ON_MASK:
|
||||
{
|
||||
if (pServerSerialDriver->wait_on_mask)
|
||||
{
|
||||
ULONG* pOutputMask = (ULONG*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
|
||||
if (nOutBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const BOOL rc = pServerSerialDriver->wait_on_mask(pComm, pOutputMask);
|
||||
|
||||
*lpBytesReturned = sizeof(ULONG);
|
||||
CommLog_Print(WLOG_DEBUG, "wait_on_mask %s -> %d",
|
||||
CommSerialEvString(*pOutputMask, buffer, sizeof(buffer)), rc);
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_QUEUE_SIZE:
|
||||
{
|
||||
if (pServerSerialDriver->set_queue_size)
|
||||
{
|
||||
SERIAL_QUEUE_SIZE* pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_QUEUE_SIZE));
|
||||
if (nInBufferSize < sizeof(SERIAL_QUEUE_SIZE))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_PURGE:
|
||||
{
|
||||
if (pServerSerialDriver->purge)
|
||||
{
|
||||
ULONG* pPurgeMask = (ULONG*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(ULONG));
|
||||
if (nInBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->purge(pComm, pPurgeMask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_COMMSTATUS:
|
||||
{
|
||||
if (pServerSerialDriver->get_commstatus)
|
||||
{
|
||||
SERIAL_STATUS* pCommstatus = (SERIAL_STATUS*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_STATUS));
|
||||
if (nOutBufferSize < sizeof(SERIAL_STATUS))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(SERIAL_STATUS);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_BREAK_ON:
|
||||
{
|
||||
if (pServerSerialDriver->set_break_on)
|
||||
{
|
||||
return pServerSerialDriver->set_break_on(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_BREAK_OFF:
|
||||
{
|
||||
if (pServerSerialDriver->set_break_off)
|
||||
{
|
||||
return pServerSerialDriver->set_break_off(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_XOFF:
|
||||
{
|
||||
if (pServerSerialDriver->set_xoff)
|
||||
{
|
||||
return pServerSerialDriver->set_xoff(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_SET_XON:
|
||||
{
|
||||
if (pServerSerialDriver->set_xon)
|
||||
{
|
||||
return pServerSerialDriver->set_xon(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_GET_DTRRTS:
|
||||
{
|
||||
if (pServerSerialDriver->get_dtrrts)
|
||||
{
|
||||
ULONG* pMask = (ULONG*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
|
||||
if (nOutBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(ULONG);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_CONFIG_SIZE:
|
||||
{
|
||||
if (pServerSerialDriver->config_size)
|
||||
{
|
||||
ULONG* pSize = (ULONG*)lpOutBuffer;
|
||||
|
||||
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
|
||||
if (nOutBufferSize < sizeof(ULONG))
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pServerSerialDriver->config_size(pComm, pSize))
|
||||
return FALSE;
|
||||
|
||||
*lpBytesReturned = sizeof(ULONG);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_IMMEDIATE_CHAR:
|
||||
{
|
||||
if (pServerSerialDriver->immediate_char)
|
||||
{
|
||||
UCHAR* pChar = (UCHAR*)lpInBuffer;
|
||||
|
||||
WINPR_ASSERT(nInBufferSize >= sizeof(UCHAR));
|
||||
if (nInBufferSize < sizeof(UCHAR))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pServerSerialDriver->immediate_char(pComm, pChar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_RESET_DEVICE:
|
||||
{
|
||||
if (pServerSerialDriver->reset_device)
|
||||
{
|
||||
return pServerSerialDriver->reset_device(pComm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CommLog_Print(
|
||||
WLOG_WARN, _T("unsupported IoControlCode=[0x%08" PRIX32 "] %s (remote serial driver: %s)"),
|
||||
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME: to be used through winpr-io's DeviceIoControl
|
||||
*
|
||||
* Any previous error as returned by GetLastError is cleared.
|
||||
*
|
||||
* ERRORS:
|
||||
* ERROR_INVALID_HANDLE
|
||||
* ERROR_INVALID_PARAMETER
|
||||
* ERROR_NOT_SUPPORTED lpOverlapped is not supported
|
||||
* ERROR_INSUFFICIENT_BUFFER
|
||||
* ERROR_CALL_NOT_IMPLEMENTED unimplemented ioctl
|
||||
*/
|
||||
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
|
||||
BOOL result = 0;
|
||||
|
||||
if (hDevice == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CommIsHandled(hDevice))
|
||||
return FALSE;
|
||||
|
||||
if (!pComm->fd)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = s_CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
|
||||
nOutBufferSize, lpBytesReturned, lpOverlapped);
|
||||
|
||||
if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
|
||||
{
|
||||
/* This might be a hint for a bug, especially when result==TRUE */
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"IoControlCode=[0x%08" PRIX32 "] %s: lpBytesReturned=%" PRIu32
|
||||
" and nOutBufferSize=%" PRIu32 " are different!",
|
||||
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), *lpBytesReturned,
|
||||
nOutBufferSize);
|
||||
}
|
||||
|
||||
if (pComm->permissive)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"[permissive]: IoControlCode=[0x%08" PRIX32 "] %s failed, ignoring",
|
||||
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode));
|
||||
}
|
||||
|
||||
return TRUE; /* always! */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
|
||||
{
|
||||
struct termios currentState = WINPR_C_ARRAY_INIT;
|
||||
size_t count = 0;
|
||||
do
|
||||
{
|
||||
const int src = tcsetattr(fd, optional_actions, termios_p);
|
||||
if (src < 0)
|
||||
{
|
||||
char buffer[64] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN, "[%" PRIuz "] tcsetattr failure, errno: %s [%d]", count,
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)), errno);
|
||||
return src;
|
||||
}
|
||||
|
||||
/* NB: tcsetattr() can succeed even if not all changes have been applied. */
|
||||
const int rrc = tcgetattr(fd, ¤tState);
|
||||
if (rrc < 0)
|
||||
{
|
||||
char buffer[64] = WINPR_C_ARRAY_INIT;
|
||||
CommLog_Print(WLOG_WARN, "[%" PRIuz "] tcgetattr failure, errno: %s [%d]", count,
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)), errno);
|
||||
return rrc;
|
||||
}
|
||||
// NOLINTNEXTLINE(bugprone-suspicious-memory-comparison,cert-exp42-c,cert-flp37-c)
|
||||
} while ((memcmp(¤tState, termios_p, sizeof(struct termios)) != 0) && (count++ < 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* comm_ioctl_modem_flag_str(ULONG flag)
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case SERIAL_MSR_DCTS:
|
||||
return "SERIAL_MSR_DCTS";
|
||||
case SERIAL_MSR_DDSR:
|
||||
return "SERIAL_MSR_DDSR";
|
||||
case SERIAL_MSR_TERI:
|
||||
return "SERIAL_MSR_TERI";
|
||||
case SERIAL_MSR_DDCD:
|
||||
return "SERIAL_MSR_DDCD";
|
||||
case SERIAL_MSR_CTS:
|
||||
return "SERIAL_MSR_CTS";
|
||||
case SERIAL_MSR_DSR:
|
||||
return "SERIAL_MSR_DSR";
|
||||
case SERIAL_MSR_RI:
|
||||
return "SERIAL_MSR_RI";
|
||||
case SERIAL_MSR_DCD:
|
||||
return "SERIAL_MSR_DCD";
|
||||
default:
|
||||
return "SERIAL_MSR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* comm_ioctl_modem_status_string(ULONG status, char* buffer, size_t size)
|
||||
{
|
||||
const ULONG flags[] = { SERIAL_MSR_DCTS, SERIAL_MSR_DDSR, SERIAL_MSR_TERI, SERIAL_MSR_DDCD,
|
||||
SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI, SERIAL_MSR_DCD
|
||||
|
||||
};
|
||||
winpr_str_append("{", buffer, size, "");
|
||||
|
||||
const char* sep = "";
|
||||
for (size_t x = 0; x < ARRAYSIZE(flags); x++)
|
||||
{
|
||||
const ULONG flag = flags[x];
|
||||
if (status & flag)
|
||||
{
|
||||
winpr_str_append(comm_ioctl_modem_flag_str(flag), buffer, size, sep);
|
||||
sep = "|";
|
||||
}
|
||||
}
|
||||
|
||||
char number[32] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(number, sizeof(number), "}[0x%08" PRIx32 "]", status);
|
||||
winpr_str_append(number, buffer, size, "");
|
||||
return buffer;
|
||||
}
|
||||
232
third_party/FreeRDP/winpr/libwinpr/comm/comm_ioctl.h
vendored
Normal file
232
third_party/FreeRDP/winpr/libwinpr/comm/comm_ioctl.h
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2011 O.S. Systems Software Ltda.
|
||||
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_COMM_IOCTL_H_
|
||||
#define WINPR_COMM_IOCTL_H_
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
#include <winpr/io.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include "comm.h"
|
||||
|
||||
/* Serial I/O Request Interface: http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx
|
||||
* Ntddser.h http://msdn.microsoft.com/en-us/cc308432.aspx
|
||||
* Ntddpar.h http://msdn.microsoft.com/en-us/cc308431.aspx
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* TODO: defines and types below are very similar to those in comm.h, keep only
|
||||
* those that differ more than the names */
|
||||
|
||||
#define STOP_BIT_1 0
|
||||
#define STOP_BITS_1_5 1
|
||||
#define STOP_BITS_2 2
|
||||
|
||||
#define NO_PARITY 0
|
||||
#define ODD_PARITY 1
|
||||
#define EVEN_PARITY 2
|
||||
#define MARK_PARITY 3
|
||||
#define SPACE_PARITY 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG BaudRate;
|
||||
} SERIAL_BAUD_RATE, *PSERIAL_BAUD_RATE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UCHAR EofChar;
|
||||
UCHAR ErrorChar;
|
||||
UCHAR BreakChar;
|
||||
UCHAR EventChar;
|
||||
UCHAR XonChar;
|
||||
UCHAR XoffChar;
|
||||
} SERIAL_CHARS, *PSERIAL_CHARS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UCHAR StopBits;
|
||||
UCHAR Parity;
|
||||
UCHAR WordLength;
|
||||
} SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG ControlHandShake;
|
||||
ULONG FlowReplace;
|
||||
ULONG XonLimit;
|
||||
ULONG XoffLimit;
|
||||
} SERIAL_HANDFLOW, *PSERIAL_HANDFLOW;
|
||||
|
||||
#define SERIAL_DTR_MASK ((ULONG)0x03)
|
||||
#define SERIAL_DTR_CONTROL ((ULONG)0x01)
|
||||
#define SERIAL_DTR_HANDSHAKE ((ULONG)0x02)
|
||||
#define SERIAL_CTS_HANDSHAKE ((ULONG)0x08)
|
||||
#define SERIAL_DSR_HANDSHAKE ((ULONG)0x10)
|
||||
#define SERIAL_DCD_HANDSHAKE ((ULONG)0x20)
|
||||
#define SERIAL_OUT_HANDSHAKEMASK ((ULONG)0x38)
|
||||
#define SERIAL_DSR_SENSITIVITY ((ULONG)0x40)
|
||||
#define SERIAL_ERROR_ABORT ((ULONG)0x80000000)
|
||||
#define SERIAL_CONTROL_INVALID ((ULONG)0x7fffff84)
|
||||
#define SERIAL_AUTO_TRANSMIT ((ULONG)0x01)
|
||||
#define SERIAL_AUTO_RECEIVE ((ULONG)0x02)
|
||||
#define SERIAL_ERROR_CHAR ((ULONG)0x04)
|
||||
#define SERIAL_NULL_STRIPPING ((ULONG)0x08)
|
||||
#define SERIAL_BREAK_CHAR ((ULONG)0x10)
|
||||
#define SERIAL_RTS_MASK ((ULONG)0xc0)
|
||||
#define SERIAL_RTS_CONTROL ((ULONG)0x40)
|
||||
#define SERIAL_RTS_HANDSHAKE ((ULONG)0x80)
|
||||
#define SERIAL_TRANSMIT_TOGGLE ((ULONG)0xc0)
|
||||
#define SERIAL_XOFF_CONTINUE ((ULONG)0x80000000)
|
||||
#define SERIAL_FLOW_INVALID ((ULONG)0x7fffff20)
|
||||
|
||||
#define SERIAL_SP_SERIALCOMM ((ULONG)0x00000001)
|
||||
|
||||
#define SERIAL_SP_UNSPECIFIED ((ULONG)0x00000000)
|
||||
#define SERIAL_SP_RS232 ((ULONG)0x00000001)
|
||||
#define SERIAL_SP_PARALLEL ((ULONG)0x00000002)
|
||||
#define SERIAL_SP_RS422 ((ULONG)0x00000003)
|
||||
#define SERIAL_SP_RS423 ((ULONG)0x00000004)
|
||||
#define SERIAL_SP_RS449 ((ULONG)0x00000005)
|
||||
#define SERIAL_SP_MODEM ((ULONG)0x00000006)
|
||||
#define SERIAL_SP_FAX ((ULONG)0x00000021)
|
||||
#define SERIAL_SP_SCANNER ((ULONG)0x00000022)
|
||||
#define SERIAL_SP_BRIDGE ((ULONG)0x00000100)
|
||||
#define SERIAL_SP_LAT ((ULONG)0x00000101)
|
||||
#define SERIAL_SP_TELNET ((ULONG)0x00000102)
|
||||
#define SERIAL_SP_X25 ((ULONG)0x00000103)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG ReadIntervalTimeout;
|
||||
ULONG ReadTotalTimeoutMultiplier;
|
||||
ULONG ReadTotalTimeoutConstant;
|
||||
ULONG WriteTotalTimeoutMultiplier;
|
||||
ULONG WriteTotalTimeoutConstant;
|
||||
} SERIAL_TIMEOUTS, *PSERIAL_TIMEOUTS;
|
||||
|
||||
#define SERIAL_MSR_DCTS 0x01
|
||||
#define SERIAL_MSR_DDSR 0x02
|
||||
#define SERIAL_MSR_TERI 0x04
|
||||
#define SERIAL_MSR_DDCD 0x08
|
||||
#define SERIAL_MSR_CTS 0x10
|
||||
#define SERIAL_MSR_DSR 0x20
|
||||
#define SERIAL_MSR_RI 0x40
|
||||
#define SERIAL_MSR_DCD 0x80
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG InSize;
|
||||
ULONG OutSize;
|
||||
} SERIAL_QUEUE_SIZE, *PSERIAL_QUEUE_SIZE;
|
||||
|
||||
#define SERIAL_PURGE_TXABORT 0x00000001
|
||||
#define SERIAL_PURGE_RXABORT 0x00000002
|
||||
#define SERIAL_PURGE_TXCLEAR 0x00000004
|
||||
#define SERIAL_PURGE_RXCLEAR 0x00000008
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Errors;
|
||||
ULONG HoldReasons;
|
||||
ULONG AmountInInQueue;
|
||||
ULONG AmountInOutQueue;
|
||||
BOOLEAN EofReceived;
|
||||
BOOLEAN WaitForImmediate;
|
||||
} SERIAL_STATUS, *PSERIAL_STATUS;
|
||||
|
||||
#define SERIAL_TX_WAITING_FOR_CTS ((ULONG)0x00000001)
|
||||
#define SERIAL_TX_WAITING_FOR_DSR ((ULONG)0x00000002)
|
||||
#define SERIAL_TX_WAITING_FOR_DCD ((ULONG)0x00000004)
|
||||
#define SERIAL_TX_WAITING_FOR_XON ((ULONG)0x00000008)
|
||||
#define SERIAL_TX_WAITING_XOFF_SENT ((ULONG)0x00000010)
|
||||
#define SERIAL_TX_WAITING_ON_BREAK ((ULONG)0x00000020)
|
||||
#define SERIAL_RX_WAITING_FOR_DSR ((ULONG)0x00000040)
|
||||
|
||||
#define SERIAL_ERROR_BREAK ((ULONG)0x00000001)
|
||||
#define SERIAL_ERROR_FRAMING ((ULONG)0x00000002)
|
||||
#define SERIAL_ERROR_OVERRUN ((ULONG)0x00000004)
|
||||
#define SERIAL_ERROR_QUEUEOVERRUN ((ULONG)0x00000008)
|
||||
#define SERIAL_ERROR_PARITY ((ULONG)0x00000010)
|
||||
|
||||
#define SERIAL_DTR_STATE ((ULONG)0x00000001)
|
||||
#define SERIAL_RTS_STATE ((ULONG)0x00000002)
|
||||
#define SERIAL_CTS_STATE ((ULONG)0x00000010)
|
||||
#define SERIAL_DSR_STATE ((ULONG)0x00000020)
|
||||
#define SERIAL_RI_STATE ((ULONG)0x00000040)
|
||||
#define SERIAL_DCD_STATE ((ULONG)0x00000080)
|
||||
|
||||
/**
|
||||
* A function might be nullptr if not supported by the underlying driver.
|
||||
*
|
||||
* FIXME: better have to use input and output buffers for all functions?
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
SERIAL_DRIVER_ID id;
|
||||
TCHAR* name;
|
||||
BOOL (*set_baud_rate)(WINPR_COMM* pComm, const SERIAL_BAUD_RATE* pBaudRate);
|
||||
BOOL (*get_baud_rate)(WINPR_COMM* pComm, SERIAL_BAUD_RATE* pBaudRate);
|
||||
BOOL (*get_properties)(WINPR_COMM* pComm, COMMPROP* pProperties);
|
||||
BOOL (*set_serial_chars)(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars);
|
||||
BOOL (*get_serial_chars)(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars);
|
||||
BOOL (*set_line_control)(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLineControl);
|
||||
BOOL (*get_line_control)(WINPR_COMM* pComm, SERIAL_LINE_CONTROL* pLineControl);
|
||||
BOOL (*set_handflow)(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow);
|
||||
BOOL (*get_handflow)(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow);
|
||||
BOOL (*set_timeouts)(WINPR_COMM* pComm, const SERIAL_TIMEOUTS* pTimeouts);
|
||||
BOOL (*get_timeouts)(WINPR_COMM* pComm, SERIAL_TIMEOUTS* pTimeouts);
|
||||
BOOL (*set_dtr)(WINPR_COMM* pComm);
|
||||
BOOL (*clear_dtr)(WINPR_COMM* pComm);
|
||||
BOOL (*set_rts)(WINPR_COMM* pComm);
|
||||
BOOL (*clear_rts)(WINPR_COMM* pComm);
|
||||
BOOL (*get_modemstatus)(WINPR_COMM* pComm, ULONG* pRegister);
|
||||
BOOL (*set_wait_mask)(WINPR_COMM* pComm, const ULONG* pWaitMask);
|
||||
BOOL (*get_wait_mask)(WINPR_COMM* pComm, ULONG* pWaitMask);
|
||||
BOOL (*wait_on_mask)(WINPR_COMM* pComm, ULONG* pOutputMask);
|
||||
BOOL (*set_queue_size)(WINPR_COMM* pComm, const SERIAL_QUEUE_SIZE* pQueueSize);
|
||||
BOOL (*purge)(WINPR_COMM* pComm, const ULONG* pPurgeMask);
|
||||
BOOL (*get_commstatus)(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus);
|
||||
BOOL (*set_break_on)(WINPR_COMM* pComm);
|
||||
BOOL (*set_break_off)(WINPR_COMM* pComm);
|
||||
BOOL (*set_xoff)(WINPR_COMM* pComm);
|
||||
BOOL (*set_xon)(WINPR_COMM* pComm);
|
||||
BOOL (*get_dtrrts)(WINPR_COMM* pComm, ULONG* pMask);
|
||||
BOOL (*config_size)(WINPR_COMM* pComm, ULONG* pSize);
|
||||
BOOL (*immediate_char)(WINPR_COMM* pComm, const UCHAR* pChar);
|
||||
BOOL (*reset_device)(WINPR_COMM* pComm);
|
||||
|
||||
} SERIAL_DRIVER;
|
||||
|
||||
int comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_COMM_IOCTL_H_ */
|
||||
87
third_party/FreeRDP/winpr/libwinpr/comm/comm_ioctl_dummy.c
vendored
Normal file
87
third_party/FreeRDP/winpr/libwinpr/comm/comm_ioctl_dummy.c
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API - Dummy implementation
|
||||
*
|
||||
* Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2024 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <winpr/comm.h>
|
||||
|
||||
#include "comm_ioctl.h"
|
||||
#include <../log.h>
|
||||
|
||||
#define TAG WINPR_TAG("comm")
|
||||
|
||||
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
WINPR_UNUSED(hDevice);
|
||||
WINPR_UNUSED(dwIoControlCode);
|
||||
WINPR_UNUSED(lpInBuffer);
|
||||
WINPR_UNUSED(nInBufferSize);
|
||||
WINPR_UNUSED(lpOutBuffer);
|
||||
WINPR_UNUSED(nOutBufferSize);
|
||||
WINPR_UNUSED(lpBytesReturned);
|
||||
WINPR_UNUSED(lpOverlapped);
|
||||
|
||||
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
|
||||
{
|
||||
WINPR_UNUSED(fd);
|
||||
WINPR_UNUSED(optional_actions);
|
||||
WINPR_UNUSED(termios_p);
|
||||
|
||||
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
|
||||
{
|
||||
WINPR_UNUSED(hDevice);
|
||||
WINPR_UNUSED(permissive);
|
||||
|
||||
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
WINPR_UNUSED(hDevice);
|
||||
WINPR_UNUSED(lpBuffer);
|
||||
WINPR_UNUSED(nNumberOfBytesToRead);
|
||||
WINPR_UNUSED(lpNumberOfBytesRead);
|
||||
WINPR_UNUSED(lpOverlapped);
|
||||
|
||||
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
WINPR_UNUSED(hDevice);
|
||||
WINPR_UNUSED(lpBuffer);
|
||||
WINPR_UNUSED(nNumberOfBytesToWrite);
|
||||
WINPR_UNUSED(lpNumberOfBytesWritten);
|
||||
WINPR_UNUSED(lpOverlapped);
|
||||
|
||||
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
|
||||
return FALSE;
|
||||
}
|
||||
210
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx2_sys.c
vendored
Normal file
210
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx2_sys.c
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2011 O.S. Systems Software Ltda.
|
||||
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include "comm_serial_sys.h"
|
||||
#include "comm_sercx_sys.h"
|
||||
|
||||
#include "comm_sercx2_sys.h"
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx
|
||||
*
|
||||
* SerCx2 does not support special characters. SerCx2 always completes
|
||||
* an IOCTL_SERIAL_SET_CHARS request with a STATUS_SUCCESS status
|
||||
* code, but does not set any special characters or perform any other
|
||||
* operation in response to this request. For an
|
||||
* IOCTL_SERIAL_GET_CHARS request, SerCx2 sets all the character
|
||||
* values in the SERIAL_CHARS structure to null, and completes the
|
||||
* request with a STATUS_SUCCESS status code.
|
||||
*/
|
||||
|
||||
static BOOL set_serial_chars(WINPR_ATTR_UNUSED WINPR_COMM* pComm,
|
||||
WINPR_ATTR_UNUSED const SERIAL_CHARS* pSerialChars)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSerialChars);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL get_serial_chars(WINPR_ATTR_UNUSED WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSerialChars);
|
||||
|
||||
ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
|
||||
/* FIXME: only using the Serial.sys' events, complete the support of the remaining events */
|
||||
static const ULONG SERCX2_SYS_SUPPORTED_EV_MASK =
|
||||
SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR |
|
||||
SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING |
|
||||
/* SERIAL_EV_PERR | */
|
||||
SERIAL_EV_RX80FULL /*|
|
||||
SERIAL_EV_EVENT1 |
|
||||
SERIAL_EV_EVENT2*/
|
||||
;
|
||||
|
||||
/* use Serial.sys for basis (not SerCx.sys) */
|
||||
static BOOL set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
{
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pWaitMask);
|
||||
WINPR_ASSERT(pSerialSys);
|
||||
|
||||
const ULONG possibleMask = *pWaitMask & SERCX2_SYS_SUPPORTED_EV_MASK;
|
||||
|
||||
if (possibleMask != *pWaitMask)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"Not all wait events supported (SerCx2.sys), requested events= 0x%08" PRIX32
|
||||
", possible events= 0x%08" PRIX32 "",
|
||||
*pWaitMask, possibleMask);
|
||||
|
||||
/* FIXME: shall we really set the possibleMask and return FALSE? */
|
||||
pComm->WaitEventMask = possibleMask;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
|
||||
return pSerialSys->set_wait_mask(pComm, pWaitMask);
|
||||
}
|
||||
|
||||
static BOOL purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
{
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pPurgeMask);
|
||||
WINPR_ASSERT(pSerialSys);
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */
|
||||
|
||||
if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT))
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"Expecting SERIAL_PURGE_RXABORT since SERIAL_PURGE_RXCLEAR is set");
|
||||
SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((*pPurgeMask & SERIAL_PURGE_TXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_TXABORT))
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"Expecting SERIAL_PURGE_TXABORT since SERIAL_PURGE_TXCLEAR is set");
|
||||
SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return pSerialSys->purge(pComm, pPurgeMask);
|
||||
}
|
||||
|
||||
/* specific functions only */
|
||||
static SERIAL_DRIVER SerCx2Sys = {
|
||||
.id = SerialDriverSerCx2Sys,
|
||||
.name = _T("SerCx2.sys"),
|
||||
.set_baud_rate = nullptr,
|
||||
.get_baud_rate = nullptr,
|
||||
.get_properties = nullptr,
|
||||
.set_serial_chars = set_serial_chars,
|
||||
.get_serial_chars = get_serial_chars,
|
||||
.set_line_control = nullptr,
|
||||
.get_line_control = nullptr,
|
||||
.set_handflow = nullptr,
|
||||
.get_handflow = nullptr,
|
||||
.set_timeouts = nullptr,
|
||||
.get_timeouts = nullptr,
|
||||
.set_dtr = nullptr,
|
||||
.clear_dtr = nullptr,
|
||||
.set_rts = nullptr,
|
||||
.clear_rts = nullptr,
|
||||
.get_modemstatus = nullptr,
|
||||
.set_wait_mask = set_wait_mask,
|
||||
.get_wait_mask = nullptr,
|
||||
.wait_on_mask = nullptr,
|
||||
.set_queue_size = nullptr,
|
||||
.purge = purge,
|
||||
.get_commstatus = nullptr,
|
||||
.set_break_on = nullptr,
|
||||
.set_break_off = nullptr,
|
||||
.set_xoff = nullptr, /* not supported by SerCx2.sys */
|
||||
.set_xon = nullptr, /* not supported by SerCx2.sys */
|
||||
.get_dtrrts = nullptr,
|
||||
.config_size = nullptr, /* not supported by SerCx2.sys */
|
||||
.immediate_char = nullptr, /* not supported by SerCx2.sys */
|
||||
.reset_device = nullptr, /* not supported by SerCx2.sys */
|
||||
};
|
||||
|
||||
const SERIAL_DRIVER* SerCx2Sys_s(void)
|
||||
{
|
||||
/* SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
const SERIAL_DRIVER* pSerCxSys = SerCxSys_s();
|
||||
if (!pSerialSys || !pSerCxSys)
|
||||
return nullptr;
|
||||
|
||||
SerCx2Sys.set_baud_rate = pSerialSys->set_baud_rate;
|
||||
SerCx2Sys.get_baud_rate = pSerialSys->get_baud_rate;
|
||||
|
||||
SerCx2Sys.get_properties = pSerialSys->get_properties;
|
||||
|
||||
SerCx2Sys.set_line_control = pSerCxSys->set_line_control;
|
||||
SerCx2Sys.get_line_control = pSerCxSys->get_line_control;
|
||||
|
||||
/* Only SERIAL_CTS_HANDSHAKE, SERIAL_RTS_CONTROL and SERIAL_RTS_HANDSHAKE flags are really
|
||||
* required by SerCx2.sys http://msdn.microsoft.com/en-us/library/jj680685%28v=vs.85%29.aspx
|
||||
*/
|
||||
SerCx2Sys.set_handflow = pSerialSys->set_handflow;
|
||||
SerCx2Sys.get_handflow = pSerialSys->get_handflow;
|
||||
|
||||
SerCx2Sys.set_timeouts = pSerialSys->set_timeouts;
|
||||
SerCx2Sys.get_timeouts = pSerialSys->get_timeouts;
|
||||
|
||||
SerCx2Sys.set_dtr = pSerialSys->set_dtr;
|
||||
SerCx2Sys.clear_dtr = pSerialSys->clear_dtr;
|
||||
|
||||
SerCx2Sys.set_rts = pSerialSys->set_rts;
|
||||
SerCx2Sys.clear_rts = pSerialSys->clear_rts;
|
||||
|
||||
SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus;
|
||||
|
||||
SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask;
|
||||
SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask;
|
||||
SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask;
|
||||
|
||||
SerCx2Sys.set_queue_size = pSerialSys->set_queue_size;
|
||||
|
||||
SerCx2Sys.get_commstatus = pSerialSys->get_commstatus;
|
||||
|
||||
SerCx2Sys.set_break_on = pSerialSys->set_break_on;
|
||||
SerCx2Sys.set_break_off = pSerialSys->set_break_off;
|
||||
|
||||
SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts;
|
||||
|
||||
return &SerCx2Sys;
|
||||
}
|
||||
36
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx2_sys.h
vendored
Normal file
36
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx2_sys.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef COMM_SERCX2_SYS_H
|
||||
#define COMM_SERCX2_SYS_H
|
||||
|
||||
#include "comm_ioctl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
const SERIAL_DRIVER* SerCx2Sys_s(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMM_SERCX2_SYS_H */
|
||||
261
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx_sys.c
vendored
Normal file
261
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx_sys.c
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2011 O.S. Systems Software Ltda.
|
||||
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include "comm_serial_sys.h"
|
||||
#include "comm_sercx_sys.h"
|
||||
|
||||
static BOOL set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
|
||||
{
|
||||
SERIAL_HANDFLOW SerCxHandflow;
|
||||
BOOL result = TRUE;
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
|
||||
memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW));
|
||||
|
||||
/* filter out unsupported bits by SerCx.sys
|
||||
*
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
|
||||
*/
|
||||
|
||||
SerCxHandflow.ControlHandShake =
|
||||
pHandflow->ControlHandShake &
|
||||
(SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
|
||||
SerCxHandflow.FlowReplace =
|
||||
pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
|
||||
|
||||
if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake)
|
||||
{
|
||||
if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace)
|
||||
{
|
||||
if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys");
|
||||
}
|
||||
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
if (!pSerialSys->set_handflow(pComm, &SerCxHandflow))
|
||||
return FALSE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
|
||||
{
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
|
||||
BOOL result = pSerialSys->get_handflow(pComm, pHandflow);
|
||||
|
||||
/* filter out unsupported bits by SerCx.sys
|
||||
*
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
|
||||
*/
|
||||
|
||||
pHandflow->ControlHandShake =
|
||||
pHandflow->ControlHandShake &
|
||||
(SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
|
||||
pHandflow->FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
|
||||
static const ULONG SERCX_SYS_SUPPORTED_EV_MASK = SERIAL_EV_RXCHAR |
|
||||
/* SERIAL_EV_RXFLAG | */
|
||||
SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR |
|
||||
SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR |
|
||||
SERIAL_EV_RING /* |
|
||||
SERIAL_EV_PERR |
|
||||
SERIAL_EV_RX80FULL |
|
||||
SERIAL_EV_EVENT1 |
|
||||
SERIAL_EV_EVENT2*/
|
||||
;
|
||||
|
||||
static BOOL set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
{
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
WINPR_ASSERT(pWaitMask);
|
||||
|
||||
const ULONG possibleMask = *pWaitMask & SERCX_SYS_SUPPORTED_EV_MASK;
|
||||
|
||||
if (possibleMask != *pWaitMask)
|
||||
{
|
||||
CommLog_Print(WLOG_WARN,
|
||||
"Not all wait events supported (SerCx.sys), requested events= 0x%08" PRIX32
|
||||
", possible events= 0x%08" PRIX32 "",
|
||||
*pWaitMask, possibleMask);
|
||||
|
||||
/* FIXME: shall we really set the possibleMask and return FALSE? */
|
||||
pComm->WaitEventMask = possibleMask;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
|
||||
return pSerialSys->set_wait_mask(pComm, pWaitMask);
|
||||
}
|
||||
|
||||
/* specific functions only */
|
||||
static SERIAL_DRIVER SerCxSys = {
|
||||
.id = SerialDriverSerCxSys,
|
||||
.name = _T("SerCx.sys"),
|
||||
.set_baud_rate = nullptr,
|
||||
.get_baud_rate = nullptr,
|
||||
.get_properties = nullptr,
|
||||
.set_serial_chars = nullptr,
|
||||
.get_serial_chars = nullptr,
|
||||
.set_line_control = nullptr,
|
||||
.get_line_control = nullptr,
|
||||
.set_handflow = set_handflow,
|
||||
.get_handflow = get_handflow,
|
||||
.set_timeouts = nullptr,
|
||||
.get_timeouts = nullptr,
|
||||
.set_dtr = nullptr,
|
||||
.clear_dtr = nullptr,
|
||||
.set_rts = nullptr,
|
||||
.clear_rts = nullptr,
|
||||
.get_modemstatus = nullptr,
|
||||
.set_wait_mask = set_wait_mask,
|
||||
.get_wait_mask = nullptr,
|
||||
.wait_on_mask = nullptr,
|
||||
.set_queue_size = nullptr,
|
||||
.purge = nullptr,
|
||||
.get_commstatus = nullptr,
|
||||
.set_break_on = nullptr,
|
||||
.set_break_off = nullptr,
|
||||
.set_xoff = nullptr,
|
||||
.set_xon = nullptr,
|
||||
.get_dtrrts = nullptr,
|
||||
.config_size = nullptr, /* not supported by SerCx.sys */
|
||||
.immediate_char = nullptr,
|
||||
.reset_device = nullptr, /* not supported by SerCx.sys */
|
||||
};
|
||||
|
||||
const SERIAL_DRIVER* SerCxSys_s(void)
|
||||
{
|
||||
/* _SerCxSys completed with inherited functions from SerialSys */
|
||||
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
if (!pSerialSys)
|
||||
return nullptr;
|
||||
|
||||
SerCxSys.set_baud_rate = pSerialSys->set_baud_rate;
|
||||
SerCxSys.get_baud_rate = pSerialSys->get_baud_rate;
|
||||
|
||||
SerCxSys.get_properties = pSerialSys->get_properties;
|
||||
|
||||
SerCxSys.set_serial_chars = pSerialSys->set_serial_chars;
|
||||
SerCxSys.get_serial_chars = pSerialSys->get_serial_chars;
|
||||
SerCxSys.set_line_control = pSerialSys->set_line_control;
|
||||
SerCxSys.get_line_control = pSerialSys->get_line_control;
|
||||
|
||||
SerCxSys.set_timeouts = pSerialSys->set_timeouts;
|
||||
SerCxSys.get_timeouts = pSerialSys->get_timeouts;
|
||||
|
||||
SerCxSys.set_dtr = pSerialSys->set_dtr;
|
||||
SerCxSys.clear_dtr = pSerialSys->clear_dtr;
|
||||
|
||||
SerCxSys.set_rts = pSerialSys->set_rts;
|
||||
SerCxSys.clear_rts = pSerialSys->clear_rts;
|
||||
|
||||
SerCxSys.get_modemstatus = pSerialSys->get_modemstatus;
|
||||
|
||||
SerCxSys.set_wait_mask = pSerialSys->set_wait_mask;
|
||||
SerCxSys.get_wait_mask = pSerialSys->get_wait_mask;
|
||||
SerCxSys.wait_on_mask = pSerialSys->wait_on_mask;
|
||||
|
||||
SerCxSys.set_queue_size = pSerialSys->set_queue_size;
|
||||
|
||||
SerCxSys.purge = pSerialSys->purge;
|
||||
|
||||
SerCxSys.get_commstatus = pSerialSys->get_commstatus;
|
||||
|
||||
SerCxSys.set_break_on = pSerialSys->set_break_on;
|
||||
SerCxSys.set_break_off = pSerialSys->set_break_off;
|
||||
|
||||
SerCxSys.set_xoff = pSerialSys->set_xoff;
|
||||
SerCxSys.set_xon = pSerialSys->set_xon;
|
||||
|
||||
SerCxSys.get_dtrrts = pSerialSys->get_dtrrts;
|
||||
|
||||
SerCxSys.immediate_char = pSerialSys->immediate_char;
|
||||
|
||||
return &SerCxSys;
|
||||
}
|
||||
36
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx_sys.h
vendored
Normal file
36
third_party/FreeRDP/winpr/libwinpr/comm/comm_sercx_sys.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef COMM_SERCX_SYS_H
|
||||
#define COMM_SERCX_SYS_H
|
||||
|
||||
#include "comm_ioctl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
const SERIAL_DRIVER* SerCxSys_s(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMM_SERCX_SYS_H */
|
||||
1666
third_party/FreeRDP/winpr/libwinpr/comm/comm_serial_sys.c
vendored
Normal file
1666
third_party/FreeRDP/winpr/libwinpr/comm/comm_serial_sys.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
third_party/FreeRDP/winpr/libwinpr/comm/comm_serial_sys.h
vendored
Normal file
36
third_party/FreeRDP/winpr/libwinpr/comm/comm_serial_sys.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef COMM_SERIAL_SYS_H
|
||||
#define COMM_SERIAL_SYS_H
|
||||
|
||||
#include "comm_ioctl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
const SERIAL_DRIVER* SerialSys_s(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMM_SERIAL_SYS_H */
|
||||
34
third_party/FreeRDP/winpr/libwinpr/comm/test/CMakeLists.txt
vendored
Normal file
34
third_party/FreeRDP/winpr/libwinpr/comm/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
set(MODULE_NAME "TestComm")
|
||||
set(MODULE_PREFIX "TEST_COMM")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestCommDevice.c
|
||||
TestCommConfig.c
|
||||
TestGetCommState.c
|
||||
TestSetCommState.c
|
||||
TestSerialChars.c
|
||||
TestControlSettings.c
|
||||
TestHandflow.c
|
||||
TestTimeouts.c
|
||||
TestCommMonitor.c
|
||||
)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
set_tests_properties(${TestName} PROPERTIES LABELS "comm")
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
151
third_party/FreeRDP/winpr/libwinpr/comm/test/TestCommConfig.c
vendored
Normal file
151
third_party/FreeRDP/winpr/libwinpr/comm/test/TestCommConfig.c
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/handle.h>
|
||||
|
||||
int TestCommConfig(int argc, char* argv[])
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
BOOL success = FALSE;
|
||||
LPCSTR lpFileName = "\\\\.\\COM1";
|
||||
COMMPROP commProp = WINPR_C_ARRAY_INIT;
|
||||
struct stat statbuf = WINPR_C_ARRAY_INIT;
|
||||
|
||||
HANDLE hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
|
||||
0, nullptr);
|
||||
|
||||
if (hComm && (hComm != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
(void)fprintf(
|
||||
stderr, "CreateFileA failure: could create a handle on a not yet defined device: %s\n",
|
||||
lpFileName);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
success = DefineCommDevice(lpFileName, "/dev/ttyS0");
|
||||
if (!success)
|
||||
{
|
||||
(void)fprintf(stderr, "DefineCommDevice failure: %s\n", lpFileName);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE, /* invalid parameter */
|
||||
nullptr, CREATE_NEW, /* invalid parameter */
|
||||
0, (HANDLE)1234); /* invalid parameter */
|
||||
if (hComm != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
(void)fprintf(
|
||||
stderr, "CreateFileA failure: could create a handle with some invalid parameters %s\n",
|
||||
lpFileName);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0,
|
||||
nullptr);
|
||||
|
||||
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
(void)fprintf(stderr, "CreateFileA failure: %s GetLastError() = 0x%08x\n", lpFileName,
|
||||
GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* TODO: a second call to CreateFileA should failed and
|
||||
* GetLastError should return ERROR_SHARING_VIOLATION */
|
||||
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
success = GetCommState(hComm, &dcb);
|
||||
if (!success)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: GetLastError() = Ox%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"BaudRate: %" PRIu32 " ByteSize: %" PRIu8 " Parity: %" PRIu8 " StopBits: %" PRIu8
|
||||
"\n",
|
||||
dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);
|
||||
|
||||
if (!GetCommProperties(hComm, &commProp))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommProperties failure: GetLastError(): 0x%08x\n",
|
||||
GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if ((commProp.dwSettableBaud & BAUD_57600) <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "BAUD_57600 unsupported!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if ((commProp.dwSettableBaud & BAUD_14400) > 0)
|
||||
{
|
||||
(void)fprintf(stderr, "BAUD_14400 supported!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dcb.BaudRate = CBR_57600;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
|
||||
success = SetCommState(hComm, &dcb);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
success = GetCommState(hComm, &dcb);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: GetLastError() = 0x%x\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) ||
|
||||
(dcb.StopBits != ONESTOPBIT))
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Got an unexpected value among: BaudRate: %" PRIu32 " ByteSize: %" PRIu8
|
||||
" Parity: %" PRIu8 " StopBits: %" PRIu8 "\n",
|
||||
dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);
|
||||
}
|
||||
|
||||
(void)CloseHandle(hComm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
115
third_party/FreeRDP/winpr/libwinpr/comm/test/TestCommDevice.c
vendored
Normal file
115
third_party/FreeRDP/winpr/libwinpr/comm/test/TestCommDevice.c
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/tchar.h>
|
||||
|
||||
static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult)
|
||||
{
|
||||
TCHAR lpTargetPath[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
BOOL result = DefineCommDevice(lpDeviceName, _T("/dev/test"));
|
||||
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
|
||||
{
|
||||
_tprintf(_T("DefineCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
|
||||
lpDeviceName, (expectedResult ? "TRUE" : "FALSE"), (result ? "TRUE" : "FALSE"));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = IsCommDevice(lpDeviceName);
|
||||
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
|
||||
{
|
||||
_tprintf(_T("IsCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
|
||||
lpDeviceName, (expectedResult ? "TRUE" : "FALSE"), (result ? "TRUE" : "FALSE"));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const size_t tclen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH);
|
||||
if (expectedResult)
|
||||
{
|
||||
const size_t tlen = _tcsnlen(lpTargetPath, ARRAYSIZE(lpTargetPath) - 1);
|
||||
if (tclen <= tlen) /* at least 2 more TCHAR are expected */
|
||||
{
|
||||
_tprintf(_T("QueryCommDevice failure: didn't find the device name: %s\n"),
|
||||
lpDeviceName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (_tcsncmp(_T("/dev/test"), lpTargetPath, ARRAYSIZE(lpTargetPath)) != 0)
|
||||
{
|
||||
_tprintf(
|
||||
_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
|
||||
lpDeviceName, _T("/dev/test"), lpTargetPath);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((tlen >= (ARRAYSIZE(lpTargetPath) - 1)) || (lpTargetPath[tlen + 1] != 0))
|
||||
{
|
||||
_tprintf(
|
||||
_T("QueryCommDevice failure: device name: %s, the second nullptr character is ")
|
||||
_T("missing at the end of the buffer\n"),
|
||||
lpDeviceName);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tclen > 0)
|
||||
{
|
||||
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: <none>, ")
|
||||
_T("result: %") _T(PRIuz) _T(" %s\n"),
|
||||
lpDeviceName, tclen, lpTargetPath);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestCommDevice(int argc, char* argv[])
|
||||
{
|
||||
if (!test_CommDevice(_T("COM0"), FALSE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!test_CommDevice(_T("COM1"), TRUE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!test_CommDevice(_T("COM1"), TRUE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!test_CommDevice(_T("COM10"), FALSE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!test_CommDevice(_T("\\\\.COM10"), FALSE))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
70
third_party/FreeRDP/winpr/libwinpr/comm/test/TestCommMonitor.c
vendored
Normal file
70
third_party/FreeRDP/winpr/libwinpr/comm/test/TestCommMonitor.c
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/handle.h>
|
||||
|
||||
int TestCommMonitor(int argc, char* argv[])
|
||||
{
|
||||
HANDLE hComm = nullptr;
|
||||
DWORD dwError = 0;
|
||||
BOOL fSuccess = 0;
|
||||
DWORD dwEvtMask = 0;
|
||||
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
|
||||
LPCSTR lpFileName = "\\\\.\\COM1";
|
||||
|
||||
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED, nullptr);
|
||||
|
||||
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
printf("CreateFileA failure: %s\n", lpFileName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fSuccess = SetCommMask(hComm, EV_CTS | EV_DSR);
|
||||
|
||||
if (!fSuccess)
|
||||
{
|
||||
printf("SetCommMask failure: GetLastError() = %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
{
|
||||
printf("CreateEvent failed: GetLastError() = %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WaitCommEvent(hComm, &dwEvtMask, &overlapped))
|
||||
{
|
||||
if (dwEvtMask & EV_DSR)
|
||||
{
|
||||
printf("EV_DSR\n");
|
||||
}
|
||||
|
||||
if (dwEvtMask & EV_CTS)
|
||||
{
|
||||
printf("EV_CTS\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dwError = GetLastError();
|
||||
|
||||
if (dwError == ERROR_IO_PENDING)
|
||||
{
|
||||
printf("ERROR_IO_PENDING\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("WaitCommEvent failure: GetLastError() = %" PRIu32 "\n", dwError);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
(void)CloseHandle(hComm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
123
third_party/FreeRDP/winpr/libwinpr/comm/test/TestControlSettings.c
vendored
Normal file
123
third_party/FreeRDP/winpr/libwinpr/comm/test/TestControlSettings.c
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "../comm.h"
|
||||
|
||||
int TestControlSettings(int argc, char* argv[])
|
||||
{
|
||||
struct stat statbuf = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
HANDLE hComm = nullptr;
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
result = DefineCommDevice("COM1", "/dev/ttyS0");
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
if (!GetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Test 1 */
|
||||
|
||||
dcb.ByteSize = 5;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
dcb.Parity = MARKPARITY;
|
||||
|
||||
if (!SetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
if (!GetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY))
|
||||
{
|
||||
(void)fprintf(stderr, "test1 failed.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Test 2 */
|
||||
|
||||
dcb.ByteSize = 8;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
dcb.Parity = NOPARITY;
|
||||
|
||||
if (!SetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
if (!GetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY))
|
||||
{
|
||||
(void)fprintf(stderr, "test2 failed.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CloseHandle(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
140
third_party/FreeRDP/winpr/libwinpr/comm/test/TestGetCommState.c
vendored
Normal file
140
third_party/FreeRDP/winpr/libwinpr/comm/test/TestGetCommState.c
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "../comm.h"
|
||||
|
||||
static BOOL test_generic(HANDLE hComm)
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
DCB* pDcb = nullptr;
|
||||
BOOL result = 0;
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (result)
|
||||
{
|
||||
printf("GetCommState failure, should have returned false because dcb.DCBlength has been "
|
||||
"let uninitialized\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB) / 2; /* improper value */
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (result)
|
||||
{
|
||||
printf("GetCommState failure, should have return false because dcb.DCBlength was not "
|
||||
"correctly initialized\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
printf("GetCommState failure: Ox%x, with adjusted DCBlength\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pDcb = (DCB*)calloc(2, sizeof(DCB));
|
||||
if (!pDcb)
|
||||
return FALSE;
|
||||
pDcb->DCBlength = sizeof(DCB) * 2;
|
||||
result = GetCommState(hComm, pDcb);
|
||||
result = result && (pDcb->DCBlength == sizeof(DCB) * 2);
|
||||
free(pDcb);
|
||||
if (!result)
|
||||
{
|
||||
printf("GetCommState failure: 0x%x, with bigger DCBlength\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestGetCommState(int argc, char* argv[])
|
||||
{
|
||||
struct stat statbuf = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
HANDLE hComm = nullptr;
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
result = DefineCommDevice("COM1", "/dev/ttyS0");
|
||||
if (!result)
|
||||
{
|
||||
printf("DefineCommDevice failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm =
|
||||
CreateFileA("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
|
||||
if (hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("CreateFileA failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
printf("test_generic failure (SerialDriverUnknown)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
printf("test_generic failure (SerialDriverSerialSys)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
printf("test_generic failure (SerialDriverSerCxSys)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
printf("test_generic failure (SerialDriverSerCx2Sys)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!CloseHandle(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
92
third_party/FreeRDP/winpr/libwinpr/comm/test/TestHandflow.c
vendored
Normal file
92
third_party/FreeRDP/winpr/libwinpr/comm/test/TestHandflow.c
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "../comm.h"
|
||||
|
||||
static BOOL test_SerialSys(HANDLE hComm)
|
||||
{
|
||||
// TMP: TODO:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestHandflow(int argc, char* argv[])
|
||||
{
|
||||
struct stat statbuf = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
HANDLE hComm = nullptr;
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
result = DefineCommDevice("COM1", "/dev/ttyS0");
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
|
||||
if (!test_SerialSys(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); */
|
||||
/* if (!test_SerCxSys(hComm)) */
|
||||
/* { */
|
||||
/* (void)fprintf(stderr, "test_SerCxSys failure\n"); */
|
||||
/* return EXIT_FAILURE; */
|
||||
/* } */
|
||||
|
||||
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); */
|
||||
/* if (!test_SerCx2Sys(hComm)) */
|
||||
/* { */
|
||||
/* (void)fprintf(stderr, "test_SerCxSys failure\n"); */
|
||||
/* return EXIT_FAILURE; */
|
||||
/* } */
|
||||
|
||||
if (!CloseHandle(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
180
third_party/FreeRDP/winpr/libwinpr/comm/test/TestSerialChars.c
vendored
Normal file
180
third_party/FreeRDP/winpr/libwinpr/comm/test/TestSerialChars.c
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "../comm.h"
|
||||
|
||||
static BOOL test_SerCxSys(HANDLE hComm)
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
UCHAR XonChar = 0;
|
||||
UCHAR XoffChar = 0;
|
||||
|
||||
struct termios currentTermios = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (tcgetattr(((WINPR_COMM*)hComm)->fd, ¤tTermios) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "tcgetattr failure.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
if (!GetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0'))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure, expected XonChar and XoffChar to be set\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* retrieve Xon/Xoff chars */
|
||||
if ((dcb.XonChar != currentTermios.c_cc[VSTART]) ||
|
||||
(dcb.XoffChar != currentTermios.c_cc[VSTOP]))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure, could not retrieve XonChar and XoffChar\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* swap XonChar/XoffChar */
|
||||
|
||||
XonChar = dcb.XonChar;
|
||||
XoffChar = dcb.XoffChar;
|
||||
dcb.XonChar = XoffChar;
|
||||
dcb.XoffChar = XonChar;
|
||||
if (!SetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
if (!GetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((dcb.XonChar != XoffChar) || (dcb.XoffChar != XonChar))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys, expected XonChar and XoffChar to be swapped\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* same XonChar / XoffChar */
|
||||
dcb.XonChar = dcb.XoffChar;
|
||||
if (SetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"test_SerCxSys failure, SetCommState() was supposed to failed because "
|
||||
"XonChar and XoffChar are the same\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (GetLastError() != ERROR_INVALID_PARAMETER)
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure, SetCommState() was supposed to failed with "
|
||||
"GetLastError()=ERROR_INVALID_PARAMETER\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_SerCx2Sys(HANDLE hComm)
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
if (!GetCommState(hComm, &dcb))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') ||
|
||||
(dcb.XonChar != '\0') || (dcb.XoffChar != '\0'))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCx2Sys failure, expected all characters to be: '\\0'\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestSerialChars(int argc, char* argv[])
|
||||
{
|
||||
struct stat statbuf = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
HANDLE hComm = nullptr;
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
result = DefineCommDevice("COM1", "/dev/ttyS0");
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
|
||||
if (!test_SerCxSys(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
|
||||
if (!test_SerCx2Sys(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!CloseHandle(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
335
third_party/FreeRDP/winpr/libwinpr/comm/test/TestSetCommState.c
vendored
Normal file
335
third_party/FreeRDP/winpr/libwinpr/comm/test/TestSetCommState.c
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "../comm.h"
|
||||
|
||||
static void init_empty_dcb(DCB* pDcb)
|
||||
{
|
||||
WINPR_ASSERT(pDcb);
|
||||
|
||||
ZeroMemory(pDcb, sizeof(DCB));
|
||||
pDcb->DCBlength = sizeof(DCB);
|
||||
pDcb->XonChar = 1;
|
||||
pDcb->XoffChar = 2;
|
||||
}
|
||||
|
||||
static BOOL test_fParity(HANDLE hComm)
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* test 1 */
|
||||
dcb.fParity = TRUE;
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!dcb.fParity)
|
||||
{
|
||||
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of TRUE\n", dcb.fParity);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* test 2 */
|
||||
dcb.fParity = FALSE;
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dcb.fParity)
|
||||
{
|
||||
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of FALSE\n", dcb.fParity);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* test 3 (redo test 1) */
|
||||
dcb.fParity = TRUE;
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!dcb.fParity)
|
||||
{
|
||||
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of TRUE\n", dcb.fParity);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_SerialSys(HANDLE hComm)
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Test 1 */
|
||||
dcb.BaudRate = CBR_115200;
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
if (dcb.BaudRate != CBR_115200)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_115200)\n",
|
||||
CBR_115200);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Test 2 using a different baud rate */
|
||||
|
||||
dcb.BaudRate = CBR_57600;
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
if (dcb.BaudRate != CBR_57600)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_57600)\n",
|
||||
CBR_57600);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Test 3 using an unsupported baud rate on Linux */
|
||||
dcb.BaudRate = CBR_128000;
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (result)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n",
|
||||
CBR_128000);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_SerCxSys(HANDLE hComm)
|
||||
{
|
||||
/* as of today there is no difference */
|
||||
return test_SerialSys(hComm);
|
||||
}
|
||||
|
||||
static BOOL test_SerCx2Sys(HANDLE hComm)
|
||||
{
|
||||
/* as of today there is no difference */
|
||||
return test_SerialSys(hComm);
|
||||
}
|
||||
|
||||
static BOOL test_generic(HANDLE hComm)
|
||||
{
|
||||
DCB dcb = WINPR_C_ARRAY_INIT;
|
||||
DCB dcb2 = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
|
||||
init_empty_dcb(&dcb);
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Checks whether we get the same information before and after SetCommState */
|
||||
memcpy(&dcb2, &dcb, sizeof(DCB));
|
||||
result = SetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = GetCommState(hComm, &dcb);
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (memcmp(&dcb, &dcb2, sizeof(DCB)) != 0)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"DCB is different after SetCommState() whereas it should have not changed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO: a more complete and generic test using GetCommProperties()
|
||||
|
||||
/* TMP: TODO: fBinary tests */
|
||||
|
||||
/* fParity tests */
|
||||
if (!test_fParity(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_fParity failure\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestSetCommState(int argc, char* argv[])
|
||||
{
|
||||
struct stat statbuf = WINPR_C_ARRAY_INIT;
|
||||
BOOL result = 0;
|
||||
HANDLE hComm = nullptr;
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
result = DefineCommDevice("COM1", "/dev/ttyS0");
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_generic failure (SerialDriverUnknown)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_generic failure (SerialDriverSerialSys)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!test_SerialSys(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerialSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_generic failure (SerialDriverSerCxSys)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!test_SerCxSys(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_generic failure (SerialDriverSerCx2Sys)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!test_SerCx2Sys(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCx2Sys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!CloseHandle(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
141
third_party/FreeRDP/winpr/libwinpr/comm/test/TestTimeouts.c
vendored
Normal file
141
third_party/FreeRDP/winpr/libwinpr/comm/test/TestTimeouts.c
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "../comm.h"
|
||||
|
||||
static BOOL test_generic(HANDLE hComm)
|
||||
{
|
||||
COMMTIMEOUTS timeouts = WINPR_C_ARRAY_INIT;
|
||||
COMMTIMEOUTS timeouts2 = WINPR_C_ARRAY_INIT;
|
||||
|
||||
timeouts.ReadIntervalTimeout = 1;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 2;
|
||||
timeouts.ReadTotalTimeoutConstant = 3;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 4;
|
||||
timeouts.WriteTotalTimeoutConstant = 5;
|
||||
|
||||
if (!SetCommTimeouts(hComm, &timeouts))
|
||||
{
|
||||
(void)fprintf(stderr, "SetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetCommTimeouts(hComm, &timeouts2))
|
||||
{
|
||||
(void)fprintf(stderr, "GetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (memcmp(&timeouts, &timeouts2, sizeof(COMMTIMEOUTS)) != 0)
|
||||
{
|
||||
(void)fprintf(stderr, "TestTimeouts failure, didn't get back the same timeouts.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* not supported combination */
|
||||
timeouts.ReadIntervalTimeout = MAXULONG;
|
||||
timeouts.ReadTotalTimeoutConstant = MAXULONG;
|
||||
if (SetCommTimeouts(hComm, &timeouts))
|
||||
{
|
||||
(void)fprintf(
|
||||
stderr,
|
||||
"SetCommTimeouts succeeded with ReadIntervalTimeout and ReadTotalTimeoutConstant "
|
||||
"set to MAXULONG. GetLastError: 0x%08x\n",
|
||||
GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INVALID_PARAMETER)
|
||||
{
|
||||
(void)fprintf(
|
||||
stderr,
|
||||
"SetCommTimeouts failure, expected GetLastError to return ERROR_INVALID_PARAMETER "
|
||||
"and got: 0x%08x\n",
|
||||
GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestTimeouts(int argc, char* argv[])
|
||||
{
|
||||
struct stat statbuf;
|
||||
BOOL result = 0;
|
||||
HANDLE hComm = nullptr;
|
||||
|
||||
if (stat("/dev/ttyS0", &statbuf) < 0)
|
||||
{
|
||||
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
result = DefineCommDevice("COM1", "/dev/ttyS0");
|
||||
if (!result)
|
||||
{
|
||||
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerialSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCxSys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
|
||||
if (!test_generic(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "test_SerCx2Sys failure\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!CloseHandle(hComm))
|
||||
{
|
||||
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user