From 82ed4f0f3873910025380118503b874f1d74e789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 2 Apr 2014 15:51:28 -0400 Subject: [PATCH 01/61] libwinpr-comm: initial stubs --- winpr/include/winpr/comm.h | 344 +++++++++++++++++++++ winpr/include/winpr/pipe.h | 1 + winpr/libwinpr/comm/CMakeLists.txt | 52 ++++ winpr/libwinpr/comm/ModuleOptions.cmake | 9 + winpr/libwinpr/comm/comm.c | 266 ++++++++++++++++ winpr/libwinpr/comm/comm.h | 39 +++ winpr/libwinpr/comm/module.def | 3 + winpr/libwinpr/comm/test/.gitignore | 2 + winpr/libwinpr/comm/test/CMakeLists.txt | 32 ++ winpr/libwinpr/comm/test/TestCommConfig.c | 66 ++++ winpr/libwinpr/comm/test/TestCommMonitor.c | 69 +++++ winpr/libwinpr/file/file.c | 24 +- winpr/libwinpr/handle/handle.c | 9 + winpr/libwinpr/handle/handle.h | 1 + 14 files changed, 916 insertions(+), 1 deletion(-) create mode 100644 winpr/include/winpr/comm.h create mode 100644 winpr/libwinpr/comm/CMakeLists.txt create mode 100644 winpr/libwinpr/comm/ModuleOptions.cmake create mode 100644 winpr/libwinpr/comm/comm.c create mode 100644 winpr/libwinpr/comm/comm.h create mode 100644 winpr/libwinpr/comm/module.def create mode 100644 winpr/libwinpr/comm/test/.gitignore create mode 100644 winpr/libwinpr/comm/test/CMakeLists.txt create mode 100644 winpr/libwinpr/comm/test/TestCommConfig.c create mode 100644 winpr/libwinpr/comm/test/TestCommMonitor.c diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h new file mode 100644 index 000000000..7179080c6 --- /dev/null +++ b/winpr/include/winpr/comm.h @@ -0,0 +1,344 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Marc-Andre Moreau + * + * 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_H +#define WINPR_COMM_H + +#include +#include + +#include + +#ifndef _WIN32 + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 + +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 + +#ifndef IGNORE +#define IGNORE 0 +#endif + +#define CBR_110 110 +#define CBR_300 300 +#define CBR_600 600 +#define CBR_1200 1200 +#define CBR_2400 2400 +#define CBR_4800 4800 +#define CBR_9600 9600 +#define CBR_14400 14400 +#define CBR_19200 19200 +#define CBR_38400 38400 +#define CBR_56000 56000 +#define CBR_57600 57600 +#define CBR_115200 115200 +#define CBR_128000 128000 +#define CBR_256000 256000 + +#define CE_RXOVER 0x0001 +#define CE_OVERRUN 0x0002 +#define CE_RXPARITY 0x0004 +#define CE_FRAME 0x0008 +#define CE_BREAK 0x0010 +#define CE_TXFULL 0x0100 +#define CE_PTO 0x0200 +#define CE_IOE 0x0400 +#define CE_DNS 0x0800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID (-1) +#define IE_OPEN (-2) +#define IE_NOPEN (-3) +#define IE_MEMORY (-4) +#define IE_DEFAULT (-5) +#define IE_HARDWARE (-10) +#define IE_BYTESIZE (-11) +#define IE_BAUDRATE (-12) + +#define EV_RXCHAR 0x0001 +#define EV_RXFLAG 0x0002 +#define EV_TXEMPTY 0x0004 +#define EV_CTS 0x0008 +#define EV_DSR 0x0010 +#define EV_RLSD 0x0020 +#define EV_BREAK 0x0040 +#define EV_ERR 0x0080 +#define EV_RING 0x0100 +#define EV_PERR 0x0200 +#define EV_RX80FULL 0x0400 +#define EV_EVENT1 0x0800 +#define EV_EVENT2 0x1000 + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define SETBREAK 8 +#define CLRBREAK 9 + +#define PURGE_TXABORT 0x0001 +#define PURGE_RXABORT 0x0002 +#define PURGE_TXCLEAR 0x0004 +#define PURGE_RXCLEAR 0x0008 + +#define LPTx 0x80 + +#define MS_CTS_ON ((DWORD)0x0010) +#define MS_DSR_ON ((DWORD)0x0020) +#define MS_RING_ON ((DWORD)0x0040) +#define MS_RLSD_ON ((DWORD)0x0080) + +#define SP_SERIALCOMM ((DWORD)0x00000001) + +#define PST_UNSPECIFIED ((DWORD)0x00000000) +#define PST_RS232 ((DWORD)0x00000001) +#define PST_PARALLELPORT ((DWORD)0x00000002) +#define PST_RS422 ((DWORD)0x00000003) +#define PST_RS423 ((DWORD)0x00000004) +#define PST_RS449 ((DWORD)0x00000005) +#define PST_MODEM ((DWORD)0x00000006) +#define PST_FAX ((DWORD)0x00000021) +#define PST_SCANNER ((DWORD)0x00000022) +#define PST_NETWORK_BRIDGE ((DWORD)0x00000100) +#define PST_LAT ((DWORD)0x00000101) +#define PST_TCPIP_TELNET ((DWORD)0x00000102) +#define PST_X25 ((DWORD)0x00000103) + +#define PCF_DTRDSR ((DWORD)0x0001) +#define PCF_RTSCTS ((DWORD)0x0002) +#define PCF_RLSD ((DWORD)0x0004) +#define PCF_PARITY_CHECK ((DWORD)0x0008) +#define PCF_XONXOFF ((DWORD)0x0010) +#define PCF_SETXCHAR ((DWORD)0x0020) +#define PCF_TOTALTIMEOUTS ((DWORD)0x0040) +#define PCF_INTTIMEOUTS ((DWORD)0x0080) +#define PCF_SPECIALCHARS ((DWORD)0x0100) +#define PCF_16BITMODE ((DWORD)0x0200) + +#define SP_PARITY ((DWORD)0x0001) +#define SP_BAUD ((DWORD)0x0002) +#define SP_DATABITS ((DWORD)0x0004) +#define SP_STOPBITS ((DWORD)0x0008) +#define SP_HANDSHAKING ((DWORD)0x0010) +#define SP_PARITY_CHECK ((DWORD)0x0020) +#define SP_RLSD ((DWORD)0x0040) + +#define BAUD_075 ((DWORD)0x00000001) +#define BAUD_110 ((DWORD)0x00000002) +#define BAUD_134_5 ((DWORD)0x00000004) +#define BAUD_150 ((DWORD)0x00000008) +#define BAUD_300 ((DWORD)0x00000010) +#define BAUD_600 ((DWORD)0x00000020) +#define BAUD_1200 ((DWORD)0x00000040) +#define BAUD_1800 ((DWORD)0x00000080) +#define BAUD_2400 ((DWORD)0x00000100) +#define BAUD_4800 ((DWORD)0x00000200) +#define BAUD_7200 ((DWORD)0x00000400) +#define BAUD_9600 ((DWORD)0x00000800) +#define BAUD_14400 ((DWORD)0x00001000) +#define BAUD_19200 ((DWORD)0x00002000) +#define BAUD_38400 ((DWORD)0x00004000) +#define BAUD_56K ((DWORD)0x00008000) +#define BAUD_128K ((DWORD)0x00010000) +#define BAUD_115200 ((DWORD)0x00020000) +#define BAUD_57600 ((DWORD)0x00040000) +#define BAUD_USER ((DWORD)0x10000000) + +#define DATABITS_5 ((WORD)0x0001) +#define DATABITS_6 ((WORD)0x0002) +#define DATABITS_7 ((WORD)0x0004) +#define DATABITS_8 ((WORD)0x0008) +#define DATABITS_16 ((WORD)0x0010) +#define DATABITS_16X ((WORD)0x0020) + +#define STOPBITS_10 ((WORD)0x0001) +#define STOPBITS_15 ((WORD)0x0002) +#define STOPBITS_20 ((WORD)0x0004) + +#define PARITY_NONE ((WORD)0x0100) +#define PARITY_ODD ((WORD)0x0200) +#define PARITY_EVEN ((WORD)0x0400) +#define PARITY_MARK ((WORD)0x0800) +#define PARITY_SPACE ((WORD)0x1000) + +#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) + +#define DTR_CONTROL_DISABLE 0x00 +#define DTR_CONTROL_ENABLE 0x01 +#define DTR_CONTROL_HANDSHAKE 0x02 + +#define RTS_CONTROL_DISABLE 0x00 +#define RTS_CONTROL_ENABLE 0x01 +#define RTS_CONTROL_HANDSHAKE 0x02 +#define RTS_CONTROL_TOGGLE 0x03 + +typedef struct _DCB +{ + DWORD DCBlength; + DWORD BaudRate; + DWORD fBinary:1; + DWORD fParity:1; + DWORD fOutxCtsFlow:1; + DWORD fOutxDsrFlow:1; + DWORD fDtrControl:2; + DWORD fDsrSensitivity:1; + DWORD fTXContinueOnXoff:1; + DWORD fOutX:1; + DWORD fInX:1; + DWORD fErrorChar:1; + DWORD fNull:1; + DWORD fRtsControl:2; + DWORD fAbortOnError:1; + DWORD fDummy2:17; + WORD wReserved; + WORD XonLim; + WORD XoffLim; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + char XonChar; + char XoffChar; + char ErrorChar; + char EofChar; + char EvtChar; + WORD wReserved1; +} DCB, *LPDCB; + +typedef struct _COMM_CONFIG +{ + DWORD dwSize; + WORD wVersion; + WORD wReserved; + DCB dcb; + DWORD dwProviderSubType; + DWORD dwProviderOffset; + DWORD dwProviderSize; + WCHAR wcProviderData[1]; +} COMMCONFIG, *LPCOMMCONFIG; + +typedef struct _COMMPROP +{ + WORD wPacketLength; + WORD wPacketVersion; + DWORD dwServiceMask; + DWORD dwReserved1; + DWORD dwMaxTxQueue; + DWORD dwMaxRxQueue; + DWORD dwMaxBaud; + DWORD dwProvSubType; + DWORD dwProvCapabilities; + DWORD dwSettableParams; + DWORD dwSettableBaud; + WORD wSettableData; + WORD wSettableStopParity; + DWORD dwCurrentTxQueue; + DWORD dwCurrentRxQueue; + DWORD dwProvSpec1; + DWORD dwProvSpec2; + WCHAR wcProvChar[1]; +} COMMPROP, *LPCOMMPROP; + +typedef struct _COMMTIMEOUTS +{ + DWORD ReadIntervalTimeout; + DWORD ReadTotalTimeoutMultiplier; + DWORD ReadTotalTimeoutConstant; + DWORD WriteTotalTimeoutMultiplier; + DWORD WriteTotalTimeoutConstant; +} COMMTIMEOUTS, *LPCOMMTIMEOUTS; + +typedef struct _COMSTAT +{ + DWORD fCtsHold:1; + DWORD fDsrHold:1; + DWORD fRlsdHold:1; + DWORD fXoffHold:1; + DWORD fXoffSent:1; + DWORD fEof:1; + DWORD fTxim:1; + DWORD fReserved:25; + DWORD cbInQue; + DWORD cbOutQue; +} COMSTAT, *LPCOMSTAT; + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB); +WINPR_API BOOL BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB); + +WINPR_API BOOL BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts); +WINPR_API BOOL BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts); + +WINPR_API BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC); +WINPR_API BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC); + +WINPR_API BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize); +WINPR_API BOOL SetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize); + +WINPR_API BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask); +WINPR_API BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask); + +WINPR_API BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat); +WINPR_API BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp); + +WINPR_API BOOL GetCommState(HANDLE hFile, LPDCB lpDCB); +WINPR_API BOOL SetCommState(HANDLE hFile, LPDCB lpDCB); + +WINPR_API BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); +WINPR_API BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); + +WINPR_API BOOL GetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize); +WINPR_API BOOL GetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize); + +WINPR_API BOOL SetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize); +WINPR_API BOOL SetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize); + +WINPR_API BOOL SetCommBreak(HANDLE hFile); +WINPR_API BOOL ClearCommBreak(HANDLE hFile); +WINPR_API BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat); + +WINPR_API BOOL PurgeComm(HANDLE hFile, DWORD dwFlags); +WINPR_API BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue); + +WINPR_API BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc); + +WINPR_API BOOL TransmitCommChar(HANDLE hFile, char cChar); + +WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif /* WINPR_COMM_H */ + diff --git a/winpr/include/winpr/pipe.h b/winpr/include/winpr/pipe.h index 5c5b12f0f..c06f299ca 100644 --- a/winpr/include/winpr/pipe.h +++ b/winpr/include/winpr/pipe.h @@ -110,6 +110,7 @@ WINPR_API BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComput * Extended API */ +WINPR_API BOOL IsNamedPipeFileNameA(LPCSTR lpName); WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(); WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); diff --git a/winpr/libwinpr/comm/CMakeLists.txt b/winpr/libwinpr/comm/CMakeLists.txt new file mode 100644 index 000000000..f13d67cff --- /dev/null +++ b/winpr/libwinpr/comm/CMakeLists.txt @@ -0,0 +1,52 @@ +# WinPR: Windows Portable Runtime +# libwinpr-comm cmake build script +# +# Copyright 2014 Marc-Andre Moreau +# +# 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") + +set(${MODULE_PREFIX}_SRCS + comm.c + comm.h) + +if(MSVC AND (NOT MONOLITHIC_BUILD)) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) +endif() + +add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" + MONOLITHIC ${MONOLITHIC_BUILD} + SOURCES ${${MODULE_PREFIX}_SRCS}) + +set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL + MODULE winpr + MODULES winpr-crt winpr-thread winpr-synch winpr-utils) + +if(MONOLITHIC_BUILD) + set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) +else() + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) +endif() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") + +if(BUILD_TESTING) + add_subdirectory(test) +endif() + diff --git a/winpr/libwinpr/comm/ModuleOptions.cmake b/winpr/libwinpr/comm/ModuleOptions.cmake new file mode 100644 index 000000000..40955892a --- /dev/null +++ b/winpr/libwinpr/comm/ModuleOptions.cmake @@ -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}") + diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c new file mode 100644 index 000000000..f91055b69 --- /dev/null +++ b/winpr/libwinpr/comm/comm.c @@ -0,0 +1,266 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +/** + * Communication Resources: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363196/ + */ + +#ifndef _WIN32 + +#include "comm.h" + +BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB) +{ + return TRUE; +} + +BOOL BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB) +{ + return TRUE; +} + +BOOL BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts) +{ + return TRUE; +} + +BOOL BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts) +{ + return TRUE; +} + +BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC) +{ + return TRUE; +} + +BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC) +{ + return TRUE; +} + +BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hCommDev; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hCommDev; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize) +{ + return TRUE; +} + +BOOL GetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize) +{ + return TRUE; +} + +BOOL SetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize) +{ + return TRUE; +} + +BOOL SetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize) +{ + return TRUE; +} + +BOOL SetCommBreak(HANDLE hFile) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL ClearCommBreak(HANDLE hFile) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL PurgeComm(HANDLE hFile, DWORD dwFlags) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL TransmitCommChar(HANDLE hFile, char cChar) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm) + return FALSE; + + return TRUE; +} + +#endif diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h new file mode 100644 index 000000000..a912b21cd --- /dev/null +++ b/winpr/libwinpr/comm/comm.h @@ -0,0 +1,39 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Marc-Andre Moreau + * + * 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 + +#ifndef _WIN32 + +#include + +#include "../handle/handle.h" + +struct winpr_comm +{ + WINPR_HANDLE_DEF(); + + int fd; +}; +typedef struct winpr_comm WINPR_COMM; + +#endif + +#endif /* WINPR_COMM_PRIVATE_H */ diff --git a/winpr/libwinpr/comm/module.def b/winpr/libwinpr/comm/module.def new file mode 100644 index 000000000..fc26e7287 --- /dev/null +++ b/winpr/libwinpr/comm/module.def @@ -0,0 +1,3 @@ +LIBRARY "libwinpr-comm" +EXPORTS + diff --git a/winpr/libwinpr/comm/test/.gitignore b/winpr/libwinpr/comm/test/.gitignore new file mode 100644 index 000000000..78bb24b78 --- /dev/null +++ b/winpr/libwinpr/comm/test/.gitignore @@ -0,0 +1,2 @@ +TestComm +TestComm.c diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt new file mode 100644 index 000000000..0291bcdc4 --- /dev/null +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -0,0 +1,32 @@ + +set(MODULE_NAME "TestComm") +set(MODULE_PREFIX "TEST_COMM") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestCommConfig.c + TestCommMonitor.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-comm winpr-crt) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +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}) +endforeach() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") + diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c new file mode 100644 index 000000000..ce128bfc2 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -0,0 +1,66 @@ + +#include +#include +#include +#include +#include + +int TestCommConfig(int argc, char* argv[]) +{ + DCB dcb; + HANDLE hComm; + BOOL fSuccess; + LPCSTR lpFileName = "\\\\.\\COM1"; + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + + if (!hComm || (hComm == INVALID_HANDLE_VALUE)) + { + printf("CreateFileA failure: %s\n", lpFileName); + return 0; + } + + ZeroMemory(&dcb, sizeof(DCB)); + + fSuccess = GetCommState(hComm, &dcb); + + if (!fSuccess) + { + printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError()); + return 0; + } + + printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + + dcb.BaudRate = CBR_57600; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; + + fSuccess = SetCommState(hComm, &dcb); + + if (!fSuccess) + { + printf("SetCommState failure: GetLastError() = %d\n", (int) GetLastError()); + return 0; + } + + fSuccess = GetCommState(hComm, &dcb); + + if (!fSuccess) + { + printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError()); + return 0; + } + + printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + + CloseHandle(hComm); + + return 0; +} + diff --git a/winpr/libwinpr/comm/test/TestCommMonitor.c b/winpr/libwinpr/comm/test/TestCommMonitor.c new file mode 100644 index 000000000..1154b2789 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestCommMonitor.c @@ -0,0 +1,69 @@ + +#include +#include +#include +#include +#include + +int TestCommMonitor(int argc, char* argv[]) +{ + HANDLE hComm; + DWORD dwError; + BOOL fSuccess; + DWORD dwEvtMask; + OVERLAPPED overlapped; + LPCSTR lpFileName = "\\\\.\\COM1"; + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (!hComm || (hComm == INVALID_HANDLE_VALUE)) + { + printf("CreateFileA failure: %s\n", lpFileName); + return 0; + } + + fSuccess = SetCommMask(hComm, EV_CTS | EV_DSR); + + if (!fSuccess) + { + printf("SetCommMask failure: GetLastError() = %d\n", (int) GetLastError()); + return 0; + } + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + 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() = %d\n", (int) dwError); + return 0; + } + } + + CloseHandle(hComm); + + return 0; +} + diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 95a71887f..9e824bd57 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -183,6 +183,7 @@ #include "../handle/handle.h" #include "../pipe/pipe.h" +#include "../comm/comm.h" #ifdef HAVE_AIO_H @@ -227,6 +228,19 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, if (!lpFileName) return INVALID_HANDLE_VALUE; + if (!IsNamedPipeFileNameA(lpFileName)) + { + HANDLE hComm; + WINPR_COMM* pComm; + + pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM)); + hComm = (HANDLE) pComm; + + WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM); + + return hComm; + } + name = GetNamedPipeNameWithoutPrefixA(lpFileName); if (!name) @@ -809,6 +823,14 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib #define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" +BOOL IsNamedPipeFileNameA(LPCSTR lpName) +{ + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return FALSE; + + return TRUE; +} + char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) { char* lpFileName; @@ -816,7 +838,7 @@ char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) if (!lpName) return NULL; - if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + if (!IsNamedPipeFileNameA(lpName)) return NULL; lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 929ee0399..7d56d9717 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -28,6 +28,7 @@ #include "../synch/synch.h" #include "../thread/thread.h" #include "../pipe/pipe.h" +#include "../comm/comm.h" #include "../security/security.h" #ifdef HAVE_UNISTD_H @@ -194,6 +195,14 @@ BOOL CloseHandle(HANDLE hObject) free(token); } + else if (Type == HANDLE_TYPE_COMM) + { + WINPR_COMM* comm; + + comm = (WINPR_COMM*) Object; + + free(comm); + } return FALSE; } diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index f9075e114..e5b6bae72 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -35,6 +35,7 @@ #define HANDLE_TYPE_FILE 10 #define HANDLE_TYPE_TIMER_QUEUE 11 #define HANDLE_TYPE_TIMER_QUEUE_TIMER 12 +#define HANDLE_TYPE_COMM 13 #define WINPR_HANDLE_DEF() \ ULONG Type From d866d37d3e856eb923a56573ef6e87cf2ae15ecd Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 9 Apr 2014 16:43:41 +0200 Subject: [PATCH 02/61] added TAGS to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5e3941bc4..66d1d93bd 100755 --- a/.gitignore +++ b/.gitignore @@ -118,3 +118,6 @@ default.log *.txt.user *.autosave + +# etags +TAGS From 75ff8fd9a45a850a1f9a76a8b506e86ac289efbe Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 18 Apr 2014 15:04:11 +0200 Subject: [PATCH 03/61] add tchar function: _tcsncmp --- winpr/include/winpr/tchar.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/winpr/include/winpr/tchar.h b/winpr/include/winpr/tchar.h index 7390ed5f3..f3525bc66 100644 --- a/winpr/include/winpr/tchar.h +++ b/winpr/include/winpr/tchar.h @@ -40,6 +40,7 @@ typedef CHAR TCHAR; #define _tcslen _wcslen #define _tcsdup _wcsdup #define _tcscmp wcscmp +#define _tcsncmp wcsncmp #define _tcscpy wcscpy #define _tcscat wcscat #define _tcschr wcschr @@ -51,6 +52,7 @@ typedef CHAR TCHAR; #define _tcslen strlen #define _tcsdup _strdup #define _tcscmp strcmp +#define _tcsncmp strncmp #define _tcscpy strcpy #define _tcscat strcat #define _tcschr strchr From f9fc107c201a9876f76e57f8620402a112c58629 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 18 Apr 2014 17:18:08 +0200 Subject: [PATCH 04/61] new functions: DefineCommDevice / QueryCommDevice / IsCommDevice --- winpr/include/winpr/comm.h | 35 ++- winpr/libwinpr/comm/CMakeLists.txt | 2 +- winpr/libwinpr/comm/comm.c | 246 +++++++++++++++++++++- winpr/libwinpr/comm/test/CMakeLists.txt | 3 +- winpr/libwinpr/comm/test/TestCommDevice.c | 115 ++++++++++ winpr/libwinpr/file/file.c | 20 +- 6 files changed, 405 insertions(+), 16 deletions(-) create mode 100644 winpr/libwinpr/comm/test/TestCommDevice.c diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 7179080c6..46f57b2f7 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -3,6 +3,7 @@ * Serial Communication API * * Copyright 2014 Marc-Andre Moreau + * 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. @@ -198,6 +199,7 @@ #define RTS_CONTROL_HANDSHAKE 0x02 #define RTS_CONTROL_TOGGLE 0x03 +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx typedef struct _DCB { DWORD DCBlength; @@ -334,11 +336,42 @@ WINPR_API BOOL TransmitCommChar(HANDLE hFile, char cChar); WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); +#ifdef UNICODE +#define BuildCommDCB BuildCommDCBW +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW +#define CommConfigDialog CommConfigDialogW +#define GetDefaultCommConfig GetDefaultCommConfigW +#define SetDefaultCommConfig SetDefaultCommConfigW +#else +#define BuildCommDCB BuildCommDCBA +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA +#define CommConfigDialog CommConfigDialogA +#define GetDefaultCommConfig GetDefaultCommConfigA +#define SetDefaultCommConfig SetDefaultCommConfigA +#endif + +/* Extended API */ + +/* + * About DefineCommDevice() / QueryDosDevice() + * + * Did something close to QueryDosDevice() and DefineDosDevice() but with + * folowing constraints: + * - mappings are stored in a static wHashTable (thread safe) + * - QueryCommDevice returns only the mappings that have been defined through DefineCommDevice() + */ +WINPR_API BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath); +WINPR_API DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax); +WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName); + +WINPR_API HANDLE _CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + #ifdef __cplusplus } #endif -#endif +#endif /* _WIN32 */ #endif /* WINPR_COMM_H */ diff --git a/winpr/libwinpr/comm/CMakeLists.txt b/winpr/libwinpr/comm/CMakeLists.txt index f13d67cff..873025f94 100644 --- a/winpr/libwinpr/comm/CMakeLists.txt +++ b/winpr/libwinpr/comm/CMakeLists.txt @@ -35,7 +35,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-crt winpr-thread winpr-synch winpr-utils) + MODULES winpr-crt winpr-file winpr-utils) if(MONOLITHIC_BUILD) set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index f91055b69..f01193dec 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -3,6 +3,7 @@ * Serial Communication API * * Copyright 2014 Marc-Andre Moreau + * 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. @@ -23,6 +24,8 @@ #include #include +#include +#include /** * Communication Resources: @@ -263,4 +266,245 @@ BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) return TRUE; } -#endif + +/* Extended API */ + +/* FIXME: DefineCommDevice / QueryCommDevice look over complicated for + * just a couple of strings, should be simplified. + * + * TODO: what about libwinpr-io.so? + */ +static wHashTable *_CommDevices = NULL; + +static int deviceNameCmp(void* pointer1, void* pointer2) +{ + return _tcscmp(pointer1, pointer2); +} + + +static int devicePathCmp(void* pointer1, void* pointer2) +{ + return _tcscmp(pointer1, pointer2); +} + +/* copied from HashTable.c */ +static unsigned long HashTable_StringHashFunctionA(void* key) +{ + int c; + unsigned long hash = 5381; + unsigned char* str = (unsigned char*) key; + + /* djb2 algorithm */ + while ((c = *str++) != '\0') + hash = (hash * 33) + c; + + return hash; +} + + +static void _CommDevicesInit() +{ + /* + * TMP: FIXME: What kind of mutex should be used here? + * better have to let DefineCommDevice() and QueryCommDevice() thread unsafe ? + * use of a module_init() ? + */ + + if (_CommDevices == NULL) + { + _CommDevices = HashTable_New(TRUE); + _CommDevices->keycmp = deviceNameCmp; + _CommDevices->valuecmp = devicePathCmp; + _CommDevices->hashFunction = HashTable_StringHashFunctionA; /* TMP: FIXME: need of a HashTable_StringHashFunctionW */ + _CommDevices->keyDeallocator = free; + _CommDevices->valueDeallocator = free; + } +} + + +static BOOL _IsReservedCommDeviceName(LPCTSTR lpName) +{ + int i; + + /* Serial ports, COM1-9 */ + for (i=1; i<10; i++) + { + TCHAR genericName[5]; + if (_stprintf_s(genericName, 5, "COM%d", i) < 0) + { + return FALSE; + } + + if (_tcscmp(genericName, lpName) == 0) + return TRUE; + } + + /* Parallel ports, LPT1-9 */ + for (i=1; i<10; i++) + { + TCHAR genericName[5]; + if (_stprintf_s(genericName, 5, "LPT%d", i) < 0) + { + return FALSE; + } + + if (_tcscmp(genericName, lpName) == 0) + return TRUE; + } + + /* TMP: TODO: PRN ? */ + + return FALSE; +} + + +/** + * Returns TRUE on success, FALSE otherwise. To get extended error + * information, call GetLastError. + * + * ERRORS: + * ERROR_OUTOFMEMORY was not possible to get mappings. + * ERROR_INVALID_DATA was not possible to add the device. + */ +BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath) +{ + LPTSTR storedDeviceName = NULL; + LPTSTR storedTargetPath = NULL; + + _CommDevicesInit(); + if (_CommDevices == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + if (_tcsncmp(lpDeviceName, _T("\\\\.\\"), 4) != 0) + { + if (!_IsReservedCommDeviceName(lpDeviceName)) + { + SetLastError(ERROR_INVALID_DATA); + goto error_handle; + } + } + + storedDeviceName = _tcsdup(lpDeviceName); + if (storedDeviceName == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + storedTargetPath = _tcsdup(lpTargetPath); + if (storedTargetPath == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + if (HashTable_Add(_CommDevices, storedDeviceName, storedTargetPath) < 0) + { + SetLastError(ERROR_INVALID_DATA); + goto error_handle; + } + + return TRUE; + + + error_handle: + if (storedDeviceName != NULL) + free(storedDeviceName); + + if (storedTargetPath != NULL) + free(storedTargetPath); + + return FALSE; +} + + +/** + * Returns the number of target paths in the buffer pointed to by + * lpTargetPath. + * + * The current implementation returns in any case 0 and 1 target + * path. A NULL lpDeviceName is not supported yet to get all the + * paths. + * + * ERRORS: + * ERROR_SUCCESS + * ERROR_OUTOFMEMORY was not possible to get mappings. + * ERROR_NOT_SUPPORTED equivalent QueryDosDevice feature not supported. + * ERROR_INVALID_DATA was not possible to retrieve any device information. + * ERROR_INSUFFICIENT_BUFFER too small lpTargetPath + */ +DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) +{ + LPTSTR storedTargetPath; + + SetLastError(ERROR_SUCCESS); + + _CommDevicesInit(); + if (_CommDevices == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + return 0; + } + + if (lpDeviceName == NULL || lpTargetPath == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + storedTargetPath = HashTable_GetItemValue(_CommDevices, (void*)lpDeviceName); + if (storedTargetPath == NULL) + { + SetLastError(ERROR_INVALID_DATA); + return 0; + } + + if (_tcslen(storedTargetPath) + 2 > ucchMax) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + _tcscpy(lpTargetPath, storedTargetPath); + _tcscat(lpTargetPath, ""); /* 2nd final '\0' */ + + return _tcslen(lpTargetPath) + 2; +} + +/** + * Checks whether lpDeviceName is a valid and registered Communication device. + */ +BOOL IsCommDevice(LPCTSTR lpDeviceName) +{ + TCHAR lpTargetPath[MAX_PATH]; + + if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0) + { + return TRUE; + } + + return FALSE; +} + + +HANDLE _CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + HANDLE hComm; + WINPR_COMM* pComm; + + //SetLastError(ERROR_BAD_PATHNAME); + + pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM)); + hComm = (HANDLE) pComm; + + WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM); + + //return INVALID_HANDLE_VALUE; + return hComm; +} + +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt index 0291bcdc4..aed5e582a 100644 --- a/winpr/libwinpr/comm/test/CMakeLists.txt +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -5,6 +5,7 @@ set(MODULE_PREFIX "TEST_COMM") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS + TestCommDevice.c TestCommConfig.c TestCommMonitor.c) @@ -17,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE winpr - MODULES winpr-comm winpr-crt) + MODULES winpr-comm winpr-crt winpr-file) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/winpr/libwinpr/comm/test/TestCommDevice.c b/winpr/libwinpr/comm/test/TestCommDevice.c new file mode 100644 index 000000000..08d8831a0 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestCommDevice.c @@ -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 + +#include +#include + +static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) +{ + BOOL result; + TCHAR lpTargetPath[MAX_PATH]; + DWORD tcslen; + + 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; + } + + tcslen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH); + if (expectedResult) + { + if (tcslen <= _tcslen(lpDeviceName)) /* at least 2 more TCHAR are expected */ + { + _tprintf(_T("QueryCommDevice failure: didn't found the device name: %s\n"), lpDeviceName); + return FALSE; + } + + if (_tcscmp(_T("/dev/test"), lpTargetPath) != 0) + { + _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"), + lpDeviceName, _T("/dev/test"), lpTargetPath); + + return FALSE; + } + + if (lpTargetPath[_tcslen(lpTargetPath) + 1] != NULL) + { + _tprintf(_T("QueryCommDevice failure: device name: %s, the second NULL character is missing at the end of the buffer\n"), lpDeviceName); + return FALSE; + } + } + else + { + if (tcslen > 0) + { + _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: , result: %d %s\n"), + lpDeviceName, tcslen, lpTargetPath); + + return FALSE; + } + } + + return TRUE; +} + + +int TestCommDevice(int argc, char* argv[]) +{ + if (!test_CommDevice(_T("COM0"), FALSE)) + return 1; + + if (!test_CommDevice(_T("COM1"), TRUE)) + return 1; + + if (!test_CommDevice(_T("COM1"), TRUE)) + return 1; + + if (!test_CommDevice(_T("COM10"), FALSE)) + return 1; + + if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE)) + return 1; + + if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE)) + return 1; + + if (!test_CommDevice(_T("\\\\.COM10"), FALSE)) + return 1; + + return 0; +} diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 9e824bd57..97cc47a78 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -3,6 +3,7 @@ * File Functions * * Copyright 2012 Marc-Andre Moreau + * 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. @@ -183,7 +184,6 @@ #include "../handle/handle.h" #include "../pipe/pipe.h" -#include "../comm/comm.h" #ifdef HAVE_AIO_H @@ -228,18 +228,14 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, if (!lpFileName) return INVALID_HANDLE_VALUE; - if (!IsNamedPipeFileNameA(lpFileName)) - { - HANDLE hComm; - WINPR_COMM* pComm; + /* TMP: TODO: */ + /* if (IsCommDevice(lpFileName)) */ + /* { */ + /* return _CommCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, */ + /* dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); */ + /* } */ - pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM)); - hComm = (HANDLE) pComm; - - WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM); - - return hComm; - } + /* FIXME: at this point lpFileName is not necessary a named pipe */ name = GetNamedPipeNameWithoutPrefixA(lpFileName); From 7e44488e0a0b209b33b7141e8bc7b7f6ae832ce6 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 18 Apr 2014 19:25:25 +0200 Subject: [PATCH 05/61] winpr-file: introduced HANDLE_CREATOR type winpr-comm: got a _CommHandleCreator --- winpr/include/winpr/comm.h | 9 ++- winpr/include/winpr/file.h | 15 ++++- winpr/libwinpr/comm/comm.c | 12 +++- winpr/libwinpr/comm/test/TestCommConfig.c | 41 ++++++++++++- winpr/libwinpr/comm/test/TestCommDevice.c | 16 ++--- winpr/libwinpr/file/file.c | 72 ++++++++++++++++++++--- 6 files changed, 141 insertions(+), 24 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 46f57b2f7..5ad90a885 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -364,8 +364,13 @@ WINPR_API BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTST WINPR_API DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax); WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName); -WINPR_API HANDLE _CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); +/** + * A handle can only be created on defined devices with DefineCommDevice(). This + * also ensures that CommCreateFileA() has been registered through + * RegisterHandleCreator(). + */ +WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); #ifdef __cplusplus } diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index a264f4f4f..696e6c65b 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -311,10 +311,23 @@ WINPR_API BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecu #define CreateDirectory CreateDirectoryA #endif -#endif /* Extra Functions */ +typedef BOOL (*pcIsHandled)(LPCSTR lpFileName); +typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +typedef struct _HANDLE_CREATOR +{ + pcIsHandled IsHandled; + pcCreateFileA CreateFileA; +} HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; + +BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator); + +#endif /* _WIN32 */ + #define WILDCARD_STAR 0x00000001 #define WILDCARD_QM 0x00000002 #define WILDCARD_DOS 0x00000100 diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index f01193dec..bd92ce028 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -276,6 +276,8 @@ BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) */ static wHashTable *_CommDevices = NULL; +static HANDLE_CREATOR *_CommHandleCreator = NULL; + static int deviceNameCmp(void* pointer1, void* pointer2) { return _tcscmp(pointer1, pointer2); @@ -318,6 +320,12 @@ static void _CommDevicesInit() _CommDevices->hashFunction = HashTable_StringHashFunctionA; /* TMP: FIXME: need of a HashTable_StringHashFunctionW */ _CommDevices->keyDeallocator = free; _CommDevices->valueDeallocator = free; + + _CommHandleCreator = (HANDLE_CREATOR*)malloc(sizeof(HANDLE_CREATOR)); + _CommHandleCreator->IsHandled = IsCommDevice; + _CommHandleCreator->CreateFileA = CommCreateFileA; + + RegisterHandleCreator(_CommHandleCreator); } } @@ -490,8 +498,8 @@ BOOL IsCommDevice(LPCTSTR lpDeviceName) } -HANDLE _CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { HANDLE hComm; WINPR_COMM* pComm; diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c index ce128bfc2..3fa717ba8 100644 --- a/winpr/libwinpr/comm/test/TestCommConfig.c +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -1,3 +1,22 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Marc-Andre Moreau + * 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 #include @@ -12,6 +31,23 @@ int TestCommConfig(int argc, char* argv[]) BOOL fSuccess; LPCSTR lpFileName = "\\\\.\\COM1"; + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + + if (hComm && (hComm != INVALID_HANDLE_VALUE)) + { + printf("CreateFileA failure: could create a handle on a not yet defined device: %s\n", lpFileName); + return EXIT_FAILURE; + } + + fSuccess = DefineCommDevice(lpFileName, "/dev/test"); + if(!fSuccess) + { + printf("DefineCommDevice failure: %s\n", lpFileName); + return EXIT_FAILURE; + } + hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -19,17 +55,16 @@ int TestCommConfig(int argc, char* argv[]) if (!hComm || (hComm == INVALID_HANDLE_VALUE)) { printf("CreateFileA failure: %s\n", lpFileName); - return 0; + return EXIT_FAILURE; } ZeroMemory(&dcb, sizeof(DCB)); fSuccess = GetCommState(hComm, &dcb); - if (!fSuccess) { printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError()); - return 0; + return EXIT_FAILURE; } printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", diff --git a/winpr/libwinpr/comm/test/TestCommDevice.c b/winpr/libwinpr/comm/test/TestCommDevice.c index 08d8831a0..4c1334728 100644 --- a/winpr/libwinpr/comm/test/TestCommDevice.c +++ b/winpr/libwinpr/comm/test/TestCommDevice.c @@ -67,7 +67,7 @@ static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) return FALSE; } - if (lpTargetPath[_tcslen(lpTargetPath) + 1] != NULL) + if (lpTargetPath[_tcslen(lpTargetPath) + 1] != 0) { _tprintf(_T("QueryCommDevice failure: device name: %s, the second NULL character is missing at the end of the buffer\n"), lpDeviceName); return FALSE; @@ -91,25 +91,25 @@ static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) int TestCommDevice(int argc, char* argv[]) { if (!test_CommDevice(_T("COM0"), FALSE)) - return 1; + return EXIT_FAILURE; if (!test_CommDevice(_T("COM1"), TRUE)) - return 1; + return EXIT_FAILURE; if (!test_CommDevice(_T("COM1"), TRUE)) - return 1; + return EXIT_FAILURE; if (!test_CommDevice(_T("COM10"), FALSE)) - return 1; + return EXIT_FAILURE; if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE)) - return 1; + return EXIT_FAILURE; if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE)) - return 1; + return EXIT_FAILURE; if (!test_CommDevice(_T("\\\\.COM10"), FALSE)) - return 1; + return EXIT_FAILURE; return 0; } diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 97cc47a78..4cacf6da1 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -185,6 +186,50 @@ #include "../pipe/pipe.h" +/* TODO: FIXME: use of a wArrayList and split winpr-utils with + * winpr-collections to avoid circular dependencies + * _HandleCreators = ArrayList_New(TRUE); + */ +static HANDLE_CREATOR **_HandleCreators = NULL; + +#define HANDLE_CREATOR_MAX 128 + +static void _HandleCreatorsInit() +{ + /* + * TMP: FIXME: What kind of mutex should be used here? use of + * a module_init()? + */ + + if (_HandleCreators == NULL) + { + _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR)); + } +} + +/** + * Returns TRUE on success, FALSE otherwise. + * + * ERRORS: + * ERROR_INSUFFICIENT_BUFFER _HandleCreators full + */ +BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator) +{ + int i; + for (i=0; iIsHandled(lpFileName)) + { + return creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + } + } + } - /* FIXME: at this point lpFileName is not necessary a named pipe */ + /* * */ + + if (!IsNamedPipeFileNameA(lpFileName)) + return INVALID_HANDLE_VALUE; name = GetNamedPipeNameWithoutPrefixA(lpFileName); From 346c598bbe81ceee8940d4ac9d1b610d094e896b Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 22 Apr 2014 17:00:14 +0200 Subject: [PATCH 06/61] Introduced RegisterHandleCreator() to be used with CreateFile() --- winpr/include/winpr/file.h | 2 +- winpr/libwinpr/file/file.c | 27 +++++++++++++++------------ winpr/libwinpr/handle/handle.c | 3 +++ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index 696e6c65b..e90019be0 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -321,7 +321,7 @@ typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD typedef struct _HANDLE_CREATOR { pcIsHandled IsHandled; - pcCreateFileA CreateFileA; + pcCreateFileA CreateFileA; /* TMP: FIXME: CreateFileA or CreateFile ? */ } HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator); diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 4cacf6da1..4908a7191 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -187,7 +187,7 @@ #include "../pipe/pipe.h" /* TODO: FIXME: use of a wArrayList and split winpr-utils with - * winpr-collections to avoid circular dependencies + * winpr-collections to avoid a circular dependency * _HandleCreators = ArrayList_New(TRUE); */ static HANDLE_CREATOR **_HandleCreators = NULL; @@ -203,7 +203,7 @@ static void _HandleCreatorsInit() if (_HandleCreators == NULL) { - _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR)); + _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*)); } } @@ -216,6 +216,9 @@ static void _HandleCreatorsInit() BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator) { int i; + + _HandleCreatorsInit(); + for (i=0; iIsHandled(lpFileName)) { - HANDLE_CREATOR *creator = (HANDLE_CREATOR*)_HandleCreators[i]; - if (creator && creator->IsHandled(lpFileName)) - { - return creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - } + return creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } } diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 7d56d9717..80d225b10 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -201,6 +201,9 @@ BOOL CloseHandle(HANDLE hObject) comm = (WINPR_COMM*) Object; + if (comm->fd > 0) + close(comm->fd); + free(comm); } From 21f9bfeb6cce5f90ab65440fd53d0b13d5dda953 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 22 Apr 2014 17:04:07 +0200 Subject: [PATCH 07/61] winpr-comm: First implementation of CommCreateFileA() winpr-comm: Implementation of GetCommState()/SetCommState() in progress (BaudRate, fBinary and fParity done) --- winpr/libwinpr/comm/comm.c | 473 +++++++++++++++++++- winpr/libwinpr/comm/test/CMakeLists.txt | 2 + winpr/libwinpr/comm/test/TestCommConfig.c | 31 +- winpr/libwinpr/comm/test/TestGetCommState.c | 88 ++++ winpr/libwinpr/comm/test/TestSetCommState.c | 215 +++++++++ 5 files changed, 786 insertions(+), 23 deletions(-) create mode 100644 winpr/libwinpr/comm/test/TestGetCommState.c create mode 100644 winpr/libwinpr/comm/test/TestSetCommState.c diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index bd92ce028..9fc551796 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -2,6 +2,8 @@ * WinPR: Windows Portable Runtime * Serial Communication API * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni * Copyright 2014 Marc-Andre Moreau * Copyright 2014 Hewlett-Packard Development Company, L.P. * @@ -22,6 +24,17 @@ #include "config.h" #endif +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include + +#include + #include #include #include @@ -32,8 +45,6 @@ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363196/ */ -#ifndef _WIN32 - #include "comm.h" BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB) @@ -126,22 +137,338 @@ BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp) return TRUE; } -BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) + +/* + * Linux, Windows speeds + * + */ +static const speed_t _SPEED_TABLE[][2] = { +#ifdef B0 + {B0, 0}, /* hang up */ +#endif +#ifdef B50 + {B50, 50}, +#endif +#ifdef B75 + {B75, 75}, +#endif +#ifdef B110 + {B110, CBR_110}, +#endif +#ifdef B134 + {B134, 134}, +#endif +#ifdef B150 + {B150, 150}, +#endif +#ifdef B200 + {B200, 200}, +#endif +#ifdef B300 + {B300, CBR_300}, +#endif +#ifdef B600 + {B600, CBR_600}, +#endif +#ifdef B1200 + {B1200, CBR_1200}, +#endif +#ifdef B1800 + {B1800, 1800}, +#endif +#ifdef B2400 + {B2400, CBR_2400}, +#endif +#ifdef B4800 + {B4800, CBR_4800}, +#endif +#ifdef B9600 + {B9600, CBR_9600}, +#endif + /* {, CBR_14400}, /\* unsupported on Linux *\/ */ +#ifdef B19200 + {B19200, CBR_19200}, +#endif +#ifdef B38400 + {B38400, CBR_38400}, +#endif + /* {, CBR_56000}, /\* unsupported on Linux *\/ */ +#ifdef B57600 + {B57600, CBR_57600}, +#endif +#ifdef B115200 + {B115200, CBR_115200}, +#endif + /* {, CBR_128000}, /\* unsupported on Linux *\/ */ + /* {, CBR_256000}, /\* unsupported on Linux *\/ */ +#ifdef B230400 + {B230400, 230400}, +#endif +#ifdef B460800 + {B460800, 460800}, +#endif +#ifdef B500000 + {B500000, 500000}, +#endif +#ifdef B576000 + {B576000, 576000}, +#endif +#ifdef B921600 + {B921600, 921600}, +#endif +#ifdef B1000000 + {B1000000, 1000000}, +#endif +#ifdef B1152000 + {B1152000, 1152000}, +#endif +#ifdef B1500000 + {B1500000, 1500000}, +#endif +#ifdef B2000000 + {B2000000, 2000000}, +#endif +#ifdef B2500000 + {B2500000, 2500000}, +#endif +#ifdef B3000000 + {B3000000, 3000000}, +#endif +#ifdef B3500000 + {B3500000, 3500000}, +#endif +#ifdef B4000000 + {B4000000, 4000000}, /* __MAX_BAUD */ +#endif +}; + + +/* Set lpDcb->BaudRate with the current baud rate. + */ +static BOOL _GetBaudRate(LPDCB lpDcb, struct termios *lpCurrentState) { - WINPR_COMM* pComm = (WINPR_COMM*) hFile; + int i; + speed_t currentSpeed; - if (!pComm) - return FALSE; + currentSpeed = cfgetispeed(lpCurrentState); - return TRUE; + for (i=0; _SPEED_TABLE[i][0]<=__MAX_BAUD; i++) + { + if (_SPEED_TABLE[i][0] == currentSpeed) + { + lpDcb->BaudRate = _SPEED_TABLE[i][1]; + return TRUE; + } + } + + DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed); + return FALSE; } -BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) + +/* Set lpFutureState's speed to lpDcb->BaudRate. + */ +static BOOL _SetBaudRate(struct termios *lpFutureState, LPDCB lpDcb) { + int i; + speed_t newSpeed; + + for (i=0; _SPEED_TABLE[i][0]<=__MAX_BAUD; i++) + { + if (_SPEED_TABLE[i][1] == lpDcb->BaudRate) + { + newSpeed = _SPEED_TABLE[i][0]; + if (cfsetspeed(lpFutureState, newSpeed) < 0) + { + DEBUG_WARN("failed to set speed 0x%x (%d)", newSpeed, lpDcb->BaudRate); + return FALSE; + } + + return TRUE; + } + } + + DEBUG_WARN("could not find a matching speed for the baud rate %d", lpDcb->BaudRate); + return FALSE; +} + +/** + * + * + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_INVALID_DATA + * ERROR_IO_DEVICE + * ERROR_OUTOFMEMORY + */ +BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) +{ + DCB *lpLocalDcb; + struct termios currentState; WINPR_COMM* pComm = (WINPR_COMM*) hFile; - if (!pComm) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } + + if (!lpDCB) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + if (lpDCB->DCBlength < sizeof(DCB)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + lpLocalDcb = (DCB*)calloc(1, lpDCB->DCBlength); + if (lpLocalDcb == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + /* error_handle */ + + lpLocalDcb->DCBlength = lpDCB->DCBlength; + + if (!_GetBaudRate(lpLocalDcb, ¤tState)) + { + SetLastError(ERROR_NOT_SUPPORTED); + goto error_handle; + } + + lpLocalDcb->fBinary = TRUE; /* TMP: should the raw mode be tested? */ + + lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; + + + memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength); + return TRUE; + + + error_handle: + if (lpLocalDcb) + free(lpLocalDcb); + + return FALSE; +} + + +/** + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_IO_DEVICE + */ +BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) +{ + struct termios futureState; + struct termios currentState; + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!lpDCB) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + ZeroMemory(&futureState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (!_SetBaudRate(&futureState, lpDCB)) + { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + + if (!lpDCB->fBinary) + { + DEBUG_WARN("unexpected nonbinary mode transfers"); + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + // TMP: set the raw mode here? + + if (lpDCB->fParity) + { + futureState.c_iflag |= INPCK; + } + else + { + futureState.c_iflag &= ~INPCK; + } + + // TMP: FIXME: validate changes according GetCommProperties + + + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx + * + * The SetCommState function reconfigures the communications + * resource, but it does not affect the internal output and + * input buffers of the specified driver. The buffers are not + * flushed, and pending read and write operations are not + * terminated prematurely. + * + * TCSANOW matches the best this definition + */ + + if (tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) + { + DEBUG_WARN("could not apply parameters, errno: %d", errno); + return FALSE; + } + + /* NB: tcsetattr() can succeed even if not all changes have been applied. */ + ZeroMemory(¤tState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (memcmp(¤tState, &futureState, sizeof(struct termios)) != 0) + { + DEBUG_WARN("all parameters were not set, doing a second attempt..."); + if (tcsetattr(pComm->fd, TCSAFLUSH, &futureState) < 0) + { + DEBUG_WARN("could not apply parameters, errno: %d", errno); + return FALSE; + } + + ZeroMemory(¤tState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (memcmp(¤tState, &futureState, sizeof(struct termios)) != 0) + { + DEBUG_WARN("Failure: all parameters were not set on a second attempt."); + SetLastError(ERROR_IO_DEVICE); + return FALSE; /* TMP: double-check whether some parameters can differ anyway */ + } + } return TRUE; } @@ -233,6 +560,15 @@ BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) if (!pComm) return FALSE; +/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx */ +/* A process reinitializes a communications resource by using the SetupComm function, which performs the following tasks: */ + +/* Terminates pending read and write operations, even if they have not been completed. */ +/* Discards unread characters and frees the internal output and input buffers of the driver associated with the specified resource. */ +/* Reallocates the internal output and input buffers. */ + +/* A process is not required to call SetupComm. If it does not, the resource's driver initializes the device with the default settings the first time that the communications resource handle is used. */ + return TRUE; } @@ -498,21 +834,126 @@ BOOL IsCommDevice(LPCTSTR lpDeviceName) } -HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, +/** + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363198%28v=vs.85%29.aspx + * + * @param lpDeviceName e.g. COM1, \\.\COM1, ... + * + * @param dwDesiredAccess expects GENERIC_READ | GENERIC_WRITE, a + * warning message is printed otherwise. TODO: better support. + * + * @param dwShareMode must be zero, INVALID_HANDLE_VALUE is returned + * otherwise and GetLastError() should return ERROR_SHARING_VIOLATION. + * + * @param lpSecurityAttributes NULL expected, a warning message is printed + * otherwise. TODO: better support. + * + * @param dwCreationDisposition must be OPEN_EXISTING. If the + * communication device doesn't exist INVALID_HANDLE_VALUE is returned + * and GetLastError() returns ERROR_FILE_NOT_FOUND. + * + * @param dwFlagsAndAttributes zero expected, a warning message is + * printed otherwise. + * + * @param hTemplateFile must be NULL. + * + * @return INVALID_HANDLE_VALUE on error. + */ +HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - HANDLE hComm; - WINPR_COMM* pComm; + CHAR devicePath[MAX_PATH]; + struct stat deviceStat; + WINPR_COMM* pComm = NULL; - //SetLastError(ERROR_BAD_PATHNAME); + + if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE)) + { + DEBUG_WARN("unexpected access to the device: 0x%x", dwDesiredAccess); + } + + if (dwShareMode != 0) + { + SetLastError(ERROR_SHARING_VIOLATION); + return INVALID_HANDLE_VALUE; + } + + /* TODO: Prevents other processes from opening a file or + * device if they request delete, read, or write access. */ + + if (lpSecurityAttributes != NULL) + { + DEBUG_WARN("unexpected security attributes: 0x%x", lpSecurityAttributes); + } + + if (dwCreationDisposition != OPEN_EXISTING) + { + SetLastError(ERROR_FILE_NOT_FOUND); /* FIXME: ERROR_NOT_SUPPORTED better? */ + return INVALID_HANDLE_VALUE; + } + + if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0) + { + /* SetLastError(GetLastError()); */ + return INVALID_HANDLE_VALUE; + } + + if (stat(devicePath, &deviceStat) < 0) + { + DEBUG_WARN("device not found %s", devicePath); + SetLastError(ERROR_FILE_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + + if (!S_ISCHR(deviceStat.st_mode)) + { + DEBUG_WARN("bad device %d", devicePath); + SetLastError(ERROR_BAD_DEVICE); + return INVALID_HANDLE_VALUE; + } + + if (dwFlagsAndAttributes != 0) + { + DEBUG_WARN("unexpected flags and attributes: 0x%x", dwFlagsAndAttributes); + } + + if (hTemplateFile != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); /* FIXME: other proper error? */ + return INVALID_HANDLE_VALUE; + } pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM)); - hComm = (HANDLE) pComm; + if (pComm == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + return INVALID_HANDLE_VALUE; + } WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM); - //return INVALID_HANDLE_VALUE; - return hComm; + /* error_handle */ + + pComm->fd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (pComm->fd < 0) + { + DEBUG_WARN("failed to open device %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + + return (HANDLE)pComm; + + + error_handle: + if (pComm != NULL) + { + CloseHandle(pComm); + } + + + return INVALID_HANDLE_VALUE; } #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt index aed5e582a..bc9bfaa8c 100644 --- a/winpr/libwinpr/comm/test/CMakeLists.txt +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -7,6 +7,8 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestCommDevice.c TestCommConfig.c + TestGetCommState.c + TestSetCommState.c TestCommMonitor.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c index 3fa717ba8..e4dcf99c7 100644 --- a/winpr/libwinpr/comm/test/TestCommConfig.c +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -32,8 +32,8 @@ int TestCommConfig(int argc, char* argv[]) LPCSTR lpFileName = "\\\\.\\COM1"; hComm = CreateFileA(lpFileName, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm && (hComm != INVALID_HANDLE_VALUE)) { @@ -41,7 +41,7 @@ int TestCommConfig(int argc, char* argv[]) return EXIT_FAILURE; } - fSuccess = DefineCommDevice(lpFileName, "/dev/test"); + fSuccess = DefineCommDevice(lpFileName, "/dev/null"); if(!fSuccess) { printf("DefineCommDevice failure: %s\n", lpFileName); @@ -49,8 +49,22 @@ int TestCommConfig(int argc, char* argv[]) } hComm = CreateFileA(lpFileName, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, /* invalid parmaeter */ + NULL, + CREATE_NEW, /* invalid parameter */ + 0, + (HANDLE)1234); /* invalid parmaeter */ + if (hComm != INVALID_HANDLE_VALUE) + { + printf("CreateFileA failure: could create a handle with some invalid parameters %s\n", lpFileName); + return EXIT_FAILURE; + } + + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (!hComm || (hComm == INVALID_HANDLE_VALUE)) { @@ -58,6 +72,9 @@ int TestCommConfig(int argc, char* argv[]) return EXIT_FAILURE; } + /* TODO: a second call to CreateFileA should failed and + * GetLastError should return ERROR_SHARING_VIOLATION */ + ZeroMemory(&dcb, sizeof(DCB)); fSuccess = GetCommState(hComm, &dcb); @@ -68,7 +85,7 @@ int TestCommConfig(int argc, char* argv[]) } printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", - (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); dcb.BaudRate = CBR_57600; dcb.ByteSize = 8; @@ -92,7 +109,7 @@ int TestCommConfig(int argc, char* argv[]) } printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", - (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); CloseHandle(hComm); diff --git a/winpr/libwinpr/comm/test/TestGetCommState.c b/winpr/libwinpr/comm/test/TestGetCommState.c new file mode 100644 index 000000000..df78215b1 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestGetCommState.c @@ -0,0 +1,88 @@ +/** + * 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 + +#include +#include + +int TestGetCommState(int argc, char* argv[]) +{ + DCB dcb, *pDcb; + BOOL result; + HANDLE hComm; + + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + printf("DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + printf("CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + 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 EXIT_FAILURE; + } + + + 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 EXIT_FAILURE; + } + + 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 EXIT_FAILURE; + } + + pDcb = (DCB*)calloc(1, sizeof(DCB) * 2); + 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 EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c new file mode 100644 index 000000000..83196e2ee --- /dev/null +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -0,0 +1,215 @@ +/** + * 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 + +#include +#include + + +static int test_fParity(HANDLE hComm) +{ + DCB dcb; + BOOL result; + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + /* test 1 */ + dcb.fParity = TRUE; + result = SetCommState(hComm, &dcb); + if (!result) + { + printf("SetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + if (!dcb.fParity) + { + printf("unexpected fParity: %d instead of TRUE\n", dcb.fParity); + return EXIT_FAILURE; + } + + /* test 2 */ + dcb.fParity = FALSE; + result = SetCommState(hComm, &dcb); + if (!result) + { + printf("SetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + if (dcb.fParity) + { + printf("unexpected fParity: %d instead of FALSE\n", dcb.fParity); + return EXIT_FAILURE; + } + + /* test 3 (redo test 1) */ + dcb.fParity = TRUE; + result = SetCommState(hComm, &dcb); + if (!result) + { + printf("SetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + if (!dcb.fParity) + { + printf("unexpected fParity: %d instead of TRUE\n", dcb.fParity); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int TestSetCommState(int argc, char* argv[]) +{ + DCB dcb, *pDcb; + BOOL result; + HANDLE hComm; + + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + printf("DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + printf("CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + dcb.BaudRate = CBR_115200; + result = SetCommState(hComm, &dcb); + if (!result) + { + printf("SetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + if (dcb.BaudRate != CBR_115200) + { + printf("SetCommState failure: could not set BaudRate=%d (CBR_115200)\n", CBR_115200); + return EXIT_FAILURE; + } + + + /* Test 2 using a defferent baud rate */ + + dcb.BaudRate = CBR_57600; + result = SetCommState(hComm, &dcb); + if (!result) + { + printf("SetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + if (dcb.BaudRate != CBR_57600) + { + printf("SetCommState failure: could not set BaudRate=%d (CBR_57600)\n", CBR_57600); + return EXIT_FAILURE; + } + + /* Test 3 using an unsupported baud rate on Linux */ +#ifdef __linux__ + dcb.BaudRate = CBR_128000; + result = SetCommState(hComm, &dcb); + if (result) + { + printf("SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n", CBR_128000); + return EXIT_FAILURE; + } +#endif /* __linux__ */ + + // TODO: a more complete and generic test using GetCommProperties() + + /* TMP: TODO: fBinary tests */ + + /* fParity tests */ + if (test_fParity(hComm) != EXIT_SUCCESS) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} From 6fcc1b44789b1a54881185da5c4577465a8d8f1f Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 25 Apr 2014 00:20:48 +0200 Subject: [PATCH 08/61] winpr-comm: first import of comm_ioctl.h and the REMOTE_SERIAL_DRIVER type. --- channels/serial/client/serial_tty.c | 18 +++ winpr/include/winpr/comm.h | 8 ++ winpr/libwinpr/comm/CMakeLists.txt | 10 +- winpr/libwinpr/comm/comm.c | 16 ++- winpr/libwinpr/comm/comm.h | 17 ++- winpr/libwinpr/comm/comm_ioctl.c | 182 ++++++++++++++++++++++++++ winpr/libwinpr/comm/comm_ioctl.h | 73 +++++++++++ winpr/libwinpr/comm/comm_sercx2_sys.c | 45 +++++++ winpr/libwinpr/comm/comm_sercx2_sys.h | 39 ++++++ winpr/libwinpr/comm/comm_sercx_sys.c | 44 +++++++ winpr/libwinpr/comm/comm_sercx_sys.h | 41 ++++++ winpr/libwinpr/comm/comm_serial_sys.c | 43 ++++++ winpr/libwinpr/comm/comm_serial_sys.h | 40 ++++++ 13 files changed, 570 insertions(+), 6 deletions(-) create mode 100644 winpr/libwinpr/comm/comm_ioctl.c create mode 100644 winpr/libwinpr/comm/comm_ioctl.h create mode 100644 winpr/libwinpr/comm/comm_sercx2_sys.c create mode 100644 winpr/libwinpr/comm/comm_sercx2_sys.h create mode 100644 winpr/libwinpr/comm/comm_sercx_sys.c create mode 100644 winpr/libwinpr/comm/comm_sercx_sys.h create mode 100644 winpr/libwinpr/comm/comm_serial_sys.c create mode 100644 winpr/libwinpr/comm/comm_serial_sys.h diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c index 8e051e930..f4a5b5178 100644 --- a/channels/serial/client/serial_tty.c +++ b/channels/serial/client/serial_tty.c @@ -101,6 +101,24 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, IoCtlAccess = ((IoControlCode >> 14) & 0x3); IoCtlDeviceType = ((IoControlCode >> 16) & 0xFFFF); + /* 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]. + */ + + /** * FILE_DEVICE_SERIAL_PORT 0x0000001B * FILE_DEVICE_UNKNOWN 0x00000022 diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 5ad90a885..8b87743dc 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -372,6 +372,14 @@ WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName); WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +/** + * FIXME: to be moved in comm_ioctl.h + */ +BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + + #ifdef __cplusplus } #endif diff --git a/winpr/libwinpr/comm/CMakeLists.txt b/winpr/libwinpr/comm/CMakeLists.txt index 873025f94..70f0c6d48 100644 --- a/winpr/libwinpr/comm/CMakeLists.txt +++ b/winpr/libwinpr/comm/CMakeLists.txt @@ -20,7 +20,15 @@ set(MODULE_PREFIX "WINPR_COMM") set(${MODULE_PREFIX}_SRCS comm.c - comm.h) + comm.h + 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) if(MSVC AND (NOT MONOLITHIC_BUILD)) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 9fc551796..7a20b1ab7 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -26,11 +26,12 @@ #ifndef _WIN32 -#include -#include #include -#include +#include +#include #include +#include + #include #include @@ -348,11 +349,12 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) goto error_handle; } - lpLocalDcb->fBinary = TRUE; /* TMP: should the raw mode be tested? */ + lpLocalDcb->fBinary = TRUE; /* TMP: TODO: seems equivalent to the raw mode */ lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; + memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength); return TRUE; @@ -943,6 +945,12 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } + /* TMP: TODO: FIXME: this information is at least need for + * get/set baud. Is possible to pull this information? to be + * forced with a comand line argument. + */ + pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; + return (HANDLE)pComm; diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index a912b21cd..1b3d41580 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -3,6 +3,7 @@ * Serial Communication API * * Copyright 2014 Marc-Andre Moreau + * 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. @@ -26,14 +27,28 @@ #include "../handle/handle.h" +/** + * IOCTLs table according the remote serial driver: + * http://msdn.microsoft.com/en-us/library/windows/hardware/dn265347%28v=vs.85%29.aspx + */ +typedef enum _REMOTE_SERIAL_DRIVER_ID +{ + RemoteSerialDriverUnknown = 0, + RemoteSerialDriverSerialSys, + RemoteSerialDriverSerCxSys, + RemoteSerialDriverSerCx2Sys /* default fallback */ +} REMOTE_SERIAL_DRIVER_ID; + struct winpr_comm { WINPR_HANDLE_DEF(); int fd; + REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; }; typedef struct winpr_comm WINPR_COMM; -#endif + +#endif /* _WIN32 */ #endif /* WINPR_COMM_PRIVATE_H */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c new file mode 100644 index 000000000..f3e4fac2b --- /dev/null +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -0,0 +1,182 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef _WIN32 + +#include + +#include + +#include "comm.h" +#include "comm_ioctl.h" +#include "comm_serial_sys.h" +#include "comm_sercx_sys.h" +#include "comm_sercx2_sys.h" + + +/** + * FIXME: to be used through winpr-io's DeviceIoControl + * + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_NOT_SUPPORTED lpOverlapped is not supported + */ +BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + PREMOTE_SERIAL_DRIVER pRemoteSerialDriver = NULL; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (lpOverlapped != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + + if (lpBytesReturned == NULL) + { + SetLastError(ERROR_INVALID_DATA); /* since we doesn't suppport lpOverlapped != NULL */ + return FALSE; + } + + *lpBytesReturned = 0; /* will be ajusted otherwise */ + + /* remoteSerialDriver to be use ... */ + switch (pComm->remoteSerialDriverId) + { + case RemoteSerialDriverSerialSys: + pRemoteSerialDriver = SerialSys(); + break; + + case RemoteSerialDriverSerCxSys: + pRemoteSerialDriver = SerCxSys(); + break; + + case RemoteSerialDriverSerCx2Sys: + pRemoteSerialDriver = SerCx2Sys(); + break; + + case RemoteSerialDriverUnknown: + default: + DEBUG_WARN("Unknown remote serial driver (%d), using SerCx2.sys", pComm->remoteSerialDriverId); + pRemoteSerialDriver = SerCx2Sys(); + break; + } + + assert(pRemoteSerialDriver != NULL); + + switch (dwIoControlCode) + { + case IOCTL_SERIAL_SET_BAUD_RATE: + { + PSERIAL_BAUD_RATE pBaudRate = (PSERIAL_BAUD_RATE)lpInBuffer; + + assert(nInBufferSize == sizeof(SERIAL_BAUD_RATE)); + if (nInBufferSize < sizeof(SERIAL_BAUD_RATE)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + if (pRemoteSerialDriver->set_baud_rate) + { + return pRemoteSerialDriver->set_baud_rate(pBaudRate); + } + else + { + DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); + return FALSE; + } + } + default: + DEBUG_WARN("unsupported IoControlCode: Ox%x", dwIoControlCode); + return FALSE; + } + + + +/* IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 */ +/* IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C */ +/* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */ +/* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */ +/* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */ +/* IOCTL_SERIAL_SET_CHARS 0x001B0058 */ +/* IOCTL_SERIAL_GET_CHARS 0x001B005C */ +/* IOCTL_SERIAL_SET_DTR 0x001B0024 */ +/* IOCTL_SERIAL_CLR_DTR 0x001B0028 */ +/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ +/* IOCTL_SERIAL_SET_RTS 0x001B0030 */ +/* IOCTL_SERIAL_CLR_RTS 0x001B0034 */ +/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ +/* IOCTL_SERIAL_SET_XON 0x001B003C */ +/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ +/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ +/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */ +/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */ +/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */ +/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */ +/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ +/* IOCTL_SERIAL_PURGE 0x001B004C */ +/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */ +/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */ +/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */ +/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ +/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ +/* IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 */ +/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ +/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ +/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */ +/* IOCTL_SERIAL_GET_STATS 0x001B008C */ +/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ +/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ +/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */ +/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */ + +/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */ +/* IOCTL_PAR_SET_INFORMATION 0x00160008 */ +/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */ +/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */ +/* IOCTL_IEEE1284_GET_MODE 0x00160014 */ +/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */ +/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */ +/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */ +/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */ +/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */ +/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ +/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ + + + return TRUE; + } + +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h new file mode 100644 index 000000000..0c6a85ea9 --- /dev/null +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -0,0 +1,73 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * 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_ + +#ifndef _WIN32 + +#include +#include +#include + +#include "comm.h" + +/* 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 + + +#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 + + + +typedef struct _SERIAL_BAUD_RATE +{ + ULONG BaudRate; +} SERIAL_BAUD_RATE, *PSERIAL_BAUD_RATE; + + +/** + * A function might be NULL if not supported by the underlying remote driver. + * + * FIXME: better have to use input and output buffers for all functions? + */ +typedef struct _REMOTE_SERIAL_DRIVER +{ + REMOTE_SERIAL_DRIVER_ID id; + TCHAR *name; + BOOL (*set_baud_rate)(PSERIAL_BAUD_RATE pBaudRate); + +} REMOTE_SERIAL_DRIVER, *PREMOTE_SERIAL_DRIVER; + + + +#ifdef __cplusplus +} +#endif + +#endif /* _WIN32 */ + +#endif /* WINPR_COMM_IOCTL_H_ */ diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c new file mode 100644 index 000000000..90f8ba5f0 --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -0,0 +1,45 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * 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 "comm_sercx2_sys.h" +#include "comm_serial_sys.h" + + +/* specific functions only */ +static REMOTE_SERIAL_DRIVER _SerCx2Sys = +{ + .id = RemoteSerialDriverSerCx2Sys, + .name = _T("SerCx2.sys"), + .set_baud_rate = NULL, +}; + + +PREMOTE_SERIAL_DRIVER SerCx2Sys() +{ + /* _SerCxSys completed with default SerialSys functions */ + PREMOTE_SERIAL_DRIVER serialSys = SerialSys(); + + _SerCx2Sys.set_baud_rate = serialSys->set_baud_rate; + + return &_SerCx2Sys; +} diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.h b/winpr/libwinpr/comm/comm_sercx2_sys.h new file mode 100644 index 000000000..c3aa53397 --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx2_sys.h @@ -0,0 +1,39 @@ +/** + * 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 + +#ifndef _WIN32 + +#include "comm_ioctl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API PREMOTE_SERIAL_DRIVER SerCx2Sys(); + +#ifdef __cplusplus +} +#endif + +#endif /* _WIN32 */ + +#endif /* COMM_SERCX2_SYS_H */ diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c new file mode 100644 index 000000000..d8072c604 --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -0,0 +1,44 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * 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 "comm_serial_sys.h" + +/* specific functions only */ +static REMOTE_SERIAL_DRIVER _SerCxSys = +{ + .id = RemoteSerialDriverSerCxSys, + .name = _T("SerCx.sys"), + .set_baud_rate = NULL, +}; + + + +PREMOTE_SERIAL_DRIVER SerCxSys() +{ + /* _SerCxSys completed with default SerialSys functions */ + PREMOTE_SERIAL_DRIVER serialSys = SerialSys(); + + _SerCxSys.set_baud_rate = serialSys->set_baud_rate; + + return &_SerCxSys; +} diff --git a/winpr/libwinpr/comm/comm_sercx_sys.h b/winpr/libwinpr/comm/comm_sercx_sys.h new file mode 100644 index 000000000..1cceb29c8 --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx_sys.h @@ -0,0 +1,41 @@ +/** + * 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 + +#ifndef _WIN32 + +#include "comm_ioctl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API PREMOTE_SERIAL_DRIVER SerCxSys(); + +#ifdef __cplusplus +} +#endif + + +#endif /* _WIN32 */ + + +#endif /* COMM_SERCX_SYS_H */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c new file mode 100644 index 000000000..3b55e1024 --- /dev/null +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -0,0 +1,43 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * 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 "comm_serial_sys.h" + +static BOOL _set_baud_rate(PSERIAL_BAUD_RATE pBaudRate) +{ + + return FALSE; +} + + +static REMOTE_SERIAL_DRIVER _SerialSys = +{ + .id = RemoteSerialDriverSerialSys, + .name = _T("Serial.sys"), + .set_baud_rate = _set_baud_rate, +}; + + +PREMOTE_SERIAL_DRIVER SerialSys() +{ + return &_SerialSys; +} diff --git a/winpr/libwinpr/comm/comm_serial_sys.h b/winpr/libwinpr/comm/comm_serial_sys.h new file mode 100644 index 000000000..a23238df5 --- /dev/null +++ b/winpr/libwinpr/comm/comm_serial_sys.h @@ -0,0 +1,40 @@ +/** + * 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 + +#ifndef _WIN32 + +#include "comm_ioctl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API PREMOTE_SERIAL_DRIVER SerialSys(); + +#ifdef __cplusplus +} +#endif + + +#endif /* _WIN32 */ + +#endif /* COMM_SERIAL_SYS_H */ From e7f0185e691548048985fba1fd547a2117e2d1f7 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Sun, 27 Apr 2014 19:41:25 +0200 Subject: [PATCH 09/61] - firt use of winpr-comm by the serial channel (not tested and not finalized) --- channels/serial/client/CMakeLists.txt | 5 + channels/serial/client/serial_main.c | 163 ++++++++++++++++++-------- channels/serial/client/serial_tty.c | 21 +--- winpr/libwinpr/comm/comm.h | 2 + winpr/libwinpr/comm/comm_ioctl.c | 18 +++ winpr/libwinpr/handle/handle.c | 4 + 6 files changed, 145 insertions(+), 68 deletions(-) diff --git a/channels/serial/client/CMakeLists.txt b/channels/serial/client/CMakeLists.txt index d170689b5..301f5e947 100644 --- a/channels/serial/client/CMakeLists.txt +++ b/channels/serial/client/CMakeLists.txt @@ -32,6 +32,11 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MODULE freerdp MODULES freerdp-utils) +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-comm) + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index ff8ff2646..efdb97849 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -44,12 +44,13 @@ #include "serial_tty.h" #include "serial_constants.h" +#include +#include #include -#include +#include #include #include -#include -#include +#include #include #include @@ -61,9 +62,12 @@ typedef struct _SERIAL_DEVICE SERIAL_DEVICE; struct _SERIAL_DEVICE { DEVICE device; + HANDLE* hComm; + // TMP: TBR char* path; SERIAL_TTY* tty; + // wLog* log; HANDLE thread; @@ -72,71 +76,75 @@ struct _SERIAL_DEVICE static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { - int status; UINT32 FileId; + + DWORD DesiredAccess; + DWORD SharedAccess; + DWORD CreateDisposition; UINT32 PathLength; - char* path = NULL; - SERIAL_TTY* tty; + + Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */ + Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ + Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ + Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */ + Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */ + Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ + Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ + Stream_Seek(irp->input, PathLength); /* Path (variable) */ - Stream_Seek_UINT32(irp->input); /* DesiredAccess (4 bytes) */ - Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ - Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* SharedAccess (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* CreateDisposition (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ + assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */ - Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ + /* CommCreateFileA current implementation expects nothing else than that */ + assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE)); + assert(SharedAccess == 0); + assert(CreateDisposition == OPEN_EXISTING); - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input), - PathLength / 2, &path, 0, NULL, NULL); + serial->hComm = CreateFile(serial->device.name, + DesiredAccess, /* GENERIC_READ | GENERIC_WRITE */ + SharedAccess, /* 0 */ + NULL, /* SecurityAttributes */ + CreateDisposition, /* OPEN_EXISTING */ + 0, /* FlagsAndAttributes */ + NULL); /* TemplateFile */ - if (status < 1) - path = (char*) calloc(1, 1); - - FileId = irp->devman->id_sequence++; - - tty = serial_tty_new(serial->path, FileId); - - if (!tty) + if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE)) { + DEBUG_WARN("CreateFile failure: %s last-error: Ox%x\n", serial->device.name, GetLastError()); + irp->IoStatus = STATUS_UNSUCCESSFUL; FileId = 0; - - DEBUG_WARN("failed to create %s", path); - } - else - { - serial->tty = tty; - DEBUG_SVC("%s(%d) created.", serial->path, FileId); + goto error_handle; } - Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ + FileId = irp->devman->id_sequence++; // TMP: !? + irp->IoStatus = STATUS_SUCCESS; - free(path); + DEBUG_SVC("%s %s (%d) created.", serial->device.name, serial->path, FileId); + + error_handle: + Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */ + Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ irp->Complete(irp); } static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) { - SERIAL_TTY* tty = serial->tty; - Stream_Seek(irp->input, 32); /* Padding (32 bytes) */ - if (!tty) + if (!CloseHandle(serial->hComm)) { + DEBUG_WARN("CloseHandle failure: %s %s (%d) closed.", serial->device.name, serial->path, irp->device->id); irp->IoStatus = STATUS_UNSUCCESSFUL; - DEBUG_WARN("tty not valid."); - } - else - { - DEBUG_SVC("%s(%d) closed.", serial->path, tty->id); - - serial_tty_free(tty); - serial->tty = NULL; + goto error_handle; } + DEBUG_SVC("%s %s (%d) closed.", serial->device.name, serial->path, irp->device->id); + + serial->hComm = NULL; + irp->IoStatus = STATUS_SUCCESS; + + error_handle: Stream_Zero(irp->output, 5); /* Padding (5 bytes) */ irp->Complete(irp); @@ -240,8 +248,10 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) { UINT32 IoControlCode; UINT32 InputBufferLength; + BYTE* InputBuffer = NULL; UINT32 OutputBufferLength; - UINT32 abortIo = SERIAL_ABORT_IO_NONE; + BYTE* OutputBuffer = NULL; + DWORD BytesReturned = 0; SERIAL_TTY* tty = serial->tty; Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */ @@ -251,16 +261,64 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) if (!tty) { - irp->IoStatus = STATUS_UNSUCCESSFUL; - OutputBufferLength = 0; - DEBUG_WARN("tty not valid."); + irp->IoStatus = STATUS_UNSUCCESSFUL; + goto error_handle; + } + + OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE)); + if (OutputBuffer == NULL) + { + irp->IoStatus = STATUS_NO_MEMORY; + goto error_handle; + } + + InputBuffer = (BYTE*)calloc(InputBufferLength, sizeof(BYTE)); + if (InputBuffer == NULL) + { + irp->IoStatus = STATUS_NO_MEMORY; + goto error_handle; + } + + /* FIXME: to be replaced by DeviceIoControl() */ + if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) + { + Stream_Write(irp->output, OutputBuffer, BytesReturned); + irp->IoStatus = STATUS_SUCCESS; } else { - irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abortIo); + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode 0x%x last-error: 0x%x", IoControlCode, GetLastError()); + + switch(GetLastError()) + { + case ERROR_INVALID_HANDLE: + irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + + case ERROR_NOT_SUPPORTED: + irp->IoStatus = STATUS_INVALID_PARAMETER; + break; + + case ERROR_INSUFFICIENT_BUFFER: + irp->IoStatus = STATUS_BUFFER_TOO_SMALL; /* TMP: better have STATUS_BUFFER_SIZE_TOO_SMALL? http://msdn.microsoft.com/en-us/library/windows/hardware/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */ + break; + + default: + DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + irp->IoStatus = STATUS_UNSUCCESSFUL; + break; + } } + error_handle: + if (InputBuffer != NULL) + free(InputBuffer); + + if (OutputBuffer != NULL) + free(OutputBuffer); + + // TMP: double check the completion, Information field irp->Complete(irp); } @@ -375,8 +433,13 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if ((name && name[0]) && (path && path[0])) { - serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); + if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) + { + DEBUG_SVC("Could not registered: %s as %s", path, name); + return -1; + } + serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); if (!serial) return -1; diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c index f4a5b5178..b1c1a92b6 100644 --- a/channels/serial/client/serial_tty.c +++ b/channels/serial/client/serial_tty.c @@ -101,30 +101,13 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, IoCtlAccess = ((IoControlCode >> 14) & 0x3); IoCtlDeviceType = ((IoControlCode >> 16) & 0xFFFF); - /* 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]. - */ - /** * FILE_DEVICE_SERIAL_PORT 0x0000001B * FILE_DEVICE_UNKNOWN 0x00000022 */ - if (IoCtlDeviceType == 0x00000022) + if (IoCtlDeviceType == 0x00000022) // TMP: !? { IoControlCode &= 0xFFFF; IoControlCode |= (0x0000001B << 16); @@ -520,6 +503,8 @@ int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length) */ void serial_tty_free(SERIAL_TTY* tty) { + // TMP: TBR + if (!tty) return; diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 1b3d41580..c9f121442 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -45,6 +45,8 @@ struct winpr_comm int fd; REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; + + /* NB: CloseHandle() has to free resources */ }; typedef struct winpr_comm WINPR_COMM; diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index f3e4fac2b..7b0404b26 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -37,12 +37,30 @@ #include "comm_sercx2_sys.h" +/* 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]. + */ + + /** * FIXME: to be used through winpr-io's DeviceIoControl * * ERRORS: * ERROR_INVALID_HANDLE * ERROR_NOT_SUPPORTED lpOverlapped is not supported + * ERROR_INSUFFICIENT_BUFFER */ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 80d225b10..855b7db59 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -194,6 +194,8 @@ BOOL CloseHandle(HANDLE hObject) free(token->Domain); free(token); + + return TRUE; } else if (Type == HANDLE_TYPE_COMM) { @@ -205,6 +207,8 @@ BOOL CloseHandle(HANDLE hObject) close(comm->fd); free(comm); + + return TRUE; } return FALSE; From 69eeeebe67533272793cc839e147ebc3a65b17ed Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 28 Apr 2014 19:57:17 +0200 Subject: [PATCH 10/61] winpr-comm: got IOCTL_SERIAL_GET_BAUD_RATE and IOCTL_SERIAL_GET_PROPERTIES (partial) winpr-comm: cleant up unit tests --- channels/serial/client/CMakeLists.txt | 6 +- channels/serial/client/serial_main.c | 1 + winpr/libwinpr/comm/comm.c | 241 ++++---------------- winpr/libwinpr/comm/comm_ioctl.c | 185 +++++++++------ winpr/libwinpr/comm/comm_ioctl.h | 61 ++++- winpr/libwinpr/comm/comm_sercx2_sys.c | 21 +- winpr/libwinpr/comm/comm_sercx2_sys.h | 2 +- winpr/libwinpr/comm/comm_sercx_sys.c | 235 ++++++++++++++++++- winpr/libwinpr/comm/comm_sercx_sys.h | 2 +- winpr/libwinpr/comm/comm_serial_sys.c | 226 +++++++++++++++++- winpr/libwinpr/comm/comm_serial_sys.h | 25 +- winpr/libwinpr/comm/test/TestCommConfig.c | 29 +-- winpr/libwinpr/comm/test/TestSetCommState.c | 3 +- 13 files changed, 721 insertions(+), 316 deletions(-) diff --git a/channels/serial/client/CMakeLists.txt b/channels/serial/client/CMakeLists.txt index 301f5e947..a919a0180 100644 --- a/channels/serial/client/CMakeLists.txt +++ b/channels/serial/client/CMakeLists.txt @@ -33,9 +33,9 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MODULES freerdp-utils) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-comm) + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-comm) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index efdb97849..a848250c6 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -4,6 +4,7 @@ * * Copyright 2011 O.S. Systems Software Ltda. * Copyright 2011 Eduardo Fiss Beloni + * 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. diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 7a20b1ab7..c810d6863 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -41,6 +41,9 @@ #include #include +#include "comm_ioctl.h" + + /** * Communication Resources: * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363196/ @@ -139,159 +142,6 @@ BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp) } -/* - * Linux, Windows speeds - * - */ -static const speed_t _SPEED_TABLE[][2] = { -#ifdef B0 - {B0, 0}, /* hang up */ -#endif -#ifdef B50 - {B50, 50}, -#endif -#ifdef B75 - {B75, 75}, -#endif -#ifdef B110 - {B110, CBR_110}, -#endif -#ifdef B134 - {B134, 134}, -#endif -#ifdef B150 - {B150, 150}, -#endif -#ifdef B200 - {B200, 200}, -#endif -#ifdef B300 - {B300, CBR_300}, -#endif -#ifdef B600 - {B600, CBR_600}, -#endif -#ifdef B1200 - {B1200, CBR_1200}, -#endif -#ifdef B1800 - {B1800, 1800}, -#endif -#ifdef B2400 - {B2400, CBR_2400}, -#endif -#ifdef B4800 - {B4800, CBR_4800}, -#endif -#ifdef B9600 - {B9600, CBR_9600}, -#endif - /* {, CBR_14400}, /\* unsupported on Linux *\/ */ -#ifdef B19200 - {B19200, CBR_19200}, -#endif -#ifdef B38400 - {B38400, CBR_38400}, -#endif - /* {, CBR_56000}, /\* unsupported on Linux *\/ */ -#ifdef B57600 - {B57600, CBR_57600}, -#endif -#ifdef B115200 - {B115200, CBR_115200}, -#endif - /* {, CBR_128000}, /\* unsupported on Linux *\/ */ - /* {, CBR_256000}, /\* unsupported on Linux *\/ */ -#ifdef B230400 - {B230400, 230400}, -#endif -#ifdef B460800 - {B460800, 460800}, -#endif -#ifdef B500000 - {B500000, 500000}, -#endif -#ifdef B576000 - {B576000, 576000}, -#endif -#ifdef B921600 - {B921600, 921600}, -#endif -#ifdef B1000000 - {B1000000, 1000000}, -#endif -#ifdef B1152000 - {B1152000, 1152000}, -#endif -#ifdef B1500000 - {B1500000, 1500000}, -#endif -#ifdef B2000000 - {B2000000, 2000000}, -#endif -#ifdef B2500000 - {B2500000, 2500000}, -#endif -#ifdef B3000000 - {B3000000, 3000000}, -#endif -#ifdef B3500000 - {B3500000, 3500000}, -#endif -#ifdef B4000000 - {B4000000, 4000000}, /* __MAX_BAUD */ -#endif -}; - - -/* Set lpDcb->BaudRate with the current baud rate. - */ -static BOOL _GetBaudRate(LPDCB lpDcb, struct termios *lpCurrentState) -{ - int i; - speed_t currentSpeed; - - currentSpeed = cfgetispeed(lpCurrentState); - - for (i=0; _SPEED_TABLE[i][0]<=__MAX_BAUD; i++) - { - if (_SPEED_TABLE[i][0] == currentSpeed) - { - lpDcb->BaudRate = _SPEED_TABLE[i][1]; - return TRUE; - } - } - - DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed); - return FALSE; -} - - -/* Set lpFutureState's speed to lpDcb->BaudRate. - */ -static BOOL _SetBaudRate(struct termios *lpFutureState, LPDCB lpDcb) -{ - int i; - speed_t newSpeed; - - for (i=0; _SPEED_TABLE[i][0]<=__MAX_BAUD; i++) - { - if (_SPEED_TABLE[i][1] == lpDcb->BaudRate) - { - newSpeed = _SPEED_TABLE[i][0]; - if (cfsetspeed(lpFutureState, newSpeed) < 0) - { - DEBUG_WARN("failed to set speed 0x%x (%d)", newSpeed, lpDcb->BaudRate); - return FALSE; - } - - return TRUE; - } - } - - DEBUG_WARN("could not find a matching speed for the baud rate %d", lpDcb->BaudRate); - return FALSE; -} /** * @@ -307,6 +157,7 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) DCB *lpLocalDcb; struct termios currentState; WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) { @@ -343,12 +194,14 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) lpLocalDcb->DCBlength = lpDCB->DCBlength; - if (!_GetBaudRate(lpLocalDcb, ¤tState)) + SERIAL_BAUD_RATE baudRate; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &baudRate, sizeof(SERIAL_BAUD_RATE), &bytesReturned, NULL)) { - SetLastError(ERROR_NOT_SUPPORTED); + DEBUG_WARN("GetCommState failure: could not get the baud rate."); goto error_handle; } - + lpLocalDcb->BaudRate = baudRate.BaudRate; + lpLocalDcb->fBinary = TRUE; /* TMP: TODO: seems equivalent to the raw mode */ lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; @@ -368,15 +221,23 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) /** + * @return TRUE on success, FALSE otherwise. + * + * As of today, SetCommState() can fail half-way with some settings + * applied and some others not. SetCommState() returns on the first + * failure met. FIXME: or is it correct? + * * ERRORS: * ERROR_INVALID_HANDLE * ERROR_IO_DEVICE */ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) { - struct termios futureState; - struct termios currentState; + struct termios upcomingTermios; WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; + + // TMP: FIXME: validate changes according GetCommProperties if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) { @@ -390,16 +251,28 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) return FALSE; } - ZeroMemory(&futureState, sizeof(struct termios)); - if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + /* NB: did the choice to call ioctls first when available and + then to setup upcomingTermios. Don't mix both stages. */ + + /** ioctl calls stage **/ + + SERIAL_BAUD_RATE baudRate; + baudRate.BaudRate = lpDCB->BaudRate; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate, sizeof(SERIAL_BAUD_RATE), NULL, 0, &bytesReturned, NULL)) { - SetLastError(ERROR_IO_DEVICE); + DEBUG_WARN("SetCommState failure: could not set the baud rate."); return FALSE; } - if (!_SetBaudRate(&futureState, lpDCB)) + + + /** upcomingTermios stage **/ + + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ { - SetLastError(ERROR_NOT_SUPPORTED); + SetLastError(ERROR_IO_DEVICE); return FALSE; } @@ -413,16 +286,13 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) if (lpDCB->fParity) { - futureState.c_iflag |= INPCK; + upcomingTermios.c_iflag |= INPCK; } else { - futureState.c_iflag &= ~INPCK; + upcomingTermios.c_iflag &= ~INPCK; } - // TMP: FIXME: validate changes according GetCommProperties - - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx * * The SetCommState function reconfigures the communications @@ -434,43 +304,12 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) * TCSANOW matches the best this definition */ - if (tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) - { - DEBUG_WARN("could not apply parameters, errno: %d", errno); - return FALSE; - } - - /* NB: tcsetattr() can succeed even if not all changes have been applied. */ - ZeroMemory(¤tState, sizeof(struct termios)); - if (tcgetattr(pComm->fd, ¤tState) < 0) + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { SetLastError(ERROR_IO_DEVICE); return FALSE; } - - if (memcmp(¤tState, &futureState, sizeof(struct termios)) != 0) - { - DEBUG_WARN("all parameters were not set, doing a second attempt..."); - if (tcsetattr(pComm->fd, TCSAFLUSH, &futureState) < 0) - { - DEBUG_WARN("could not apply parameters, errno: %d", errno); - return FALSE; - } - - ZeroMemory(¤tState, sizeof(struct termios)); - if (tcgetattr(pComm->fd, ¤tState) < 0) - { - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } - - if (memcmp(¤tState, &futureState, sizeof(struct termios)) != 0) - { - DEBUG_WARN("Failure: all parameters were not set on a second attempt."); - SetLastError(ERROR_IO_DEVICE); - return FALSE; /* TMP: double-check whether some parameters can differ anyway */ - } - } + return TRUE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 7b0404b26..a5916e9e7 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -26,7 +26,9 @@ #ifndef _WIN32 + #include +#include #include @@ -67,7 +69,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; - PREMOTE_SERIAL_DRIVER pRemoteSerialDriver = NULL; + REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) { @@ -87,27 +89,30 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe return FALSE; } - *lpBytesReturned = 0; /* will be ajusted otherwise */ + *lpBytesReturned = 0; /* will be ajusted if required ... */ - /* remoteSerialDriver to be use ... */ + /* remoteSerialDriver to be use ... + * + * FIXME: might prefer to use an automatic rather than static structure + */ switch (pComm->remoteSerialDriverId) { case RemoteSerialDriverSerialSys: - pRemoteSerialDriver = SerialSys(); + pRemoteSerialDriver = SerialSys_s(); break; case RemoteSerialDriverSerCxSys: - pRemoteSerialDriver = SerCxSys(); + pRemoteSerialDriver = SerCxSys_s(); break; case RemoteSerialDriverSerCx2Sys: - pRemoteSerialDriver = SerCx2Sys(); + pRemoteSerialDriver = SerCx2Sys_s(); break; case RemoteSerialDriverUnknown: default: DEBUG_WARN("Unknown remote serial driver (%d), using SerCx2.sys", pComm->remoteSerialDriverId); - pRemoteSerialDriver = SerCx2Sys(); + pRemoteSerialDriver = SerCx2Sys_s(); break; } @@ -117,84 +122,112 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe { case IOCTL_SERIAL_SET_BAUD_RATE: { - PSERIAL_BAUD_RATE pBaudRate = (PSERIAL_BAUD_RATE)lpInBuffer; - - assert(nInBufferSize == sizeof(SERIAL_BAUD_RATE)); - if (nInBufferSize < sizeof(SERIAL_BAUD_RATE)) - { - SetLastError(ERROR_INVALID_DATA); - return FALSE; - } - if (pRemoteSerialDriver->set_baud_rate) { - return pRemoteSerialDriver->set_baud_rate(pBaudRate); - } - else - { - DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); - return FALSE; + SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_BAUD_RATE)); + if (nInBufferSize < sizeof(SERIAL_BAUD_RATE)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + return pRemoteSerialDriver->set_baud_rate(pComm, pBaudRate); + } + } + case IOCTL_SERIAL_GET_BAUD_RATE: + { + if (pRemoteSerialDriver->get_baud_rate) + { + SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE)); + if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_baud_rate(pComm, pBaudRate)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_BAUD_RATE); + return TRUE; + } + } + case IOCTL_SERIAL_GET_PROPERTIES: + { + if (pRemoteSerialDriver->get_properties) + { + COMMPROP *pProperties = (COMMPROP*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(COMMPROP)); + if (nOutBufferSize < sizeof(COMMPROP)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_properties(pComm, pProperties)) + return FALSE; + + *lpBytesReturned = sizeof(COMMPROP); + return TRUE; } } - default: - DEBUG_WARN("unsupported IoControlCode: Ox%x", dwIoControlCode); - return FALSE; } + DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); + return FALSE; + +} -/* IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 */ -/* IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C */ -/* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */ -/* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */ -/* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */ -/* IOCTL_SERIAL_SET_CHARS 0x001B0058 */ -/* IOCTL_SERIAL_GET_CHARS 0x001B005C */ -/* IOCTL_SERIAL_SET_DTR 0x001B0024 */ -/* IOCTL_SERIAL_CLR_DTR 0x001B0028 */ -/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ -/* IOCTL_SERIAL_SET_RTS 0x001B0030 */ -/* IOCTL_SERIAL_CLR_RTS 0x001B0034 */ -/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ -/* IOCTL_SERIAL_SET_XON 0x001B003C */ -/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ -/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ -/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */ -/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */ -/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */ -/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */ -/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ -/* IOCTL_SERIAL_PURGE 0x001B004C */ -/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */ -/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */ -/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */ -/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ -/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ -/* IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 */ -/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ -/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ -/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */ -/* IOCTL_SERIAL_GET_STATS 0x001B008C */ -/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ -/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ -/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */ -/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */ +int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p) +{ + int result; + struct termios currentState; -/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */ -/* IOCTL_PAR_SET_INFORMATION 0x00160008 */ -/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */ -/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */ -/* IOCTL_IEEE1284_GET_MODE 0x00160014 */ -/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */ -/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */ -/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */ -/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */ -/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */ -/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ -/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ - - - return TRUE; + if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0) + { + DEBUG_WARN("tcsetattr failure, errno: %d", errno); + return result; } + /* NB: tcsetattr() can succeed even if not all changes have been applied. */ + ZeroMemory(¤tState, sizeof(struct termios)); + if ((result = tcgetattr(fd, ¤tState)) < 0) + { + DEBUG_WARN("tcgetattr failure, errno: %d", errno); + return result; + } + + if (memcmp(¤tState, &termios_p, sizeof(struct termios)) != 0) + { + DEBUG_WARN("all termios parameters were not set, doing a second attempt..."); + if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0) + { + DEBUG_WARN("2nd tcsetattr failure, errno: %d", errno); + return result; + } + + ZeroMemory(¤tState, sizeof(struct termios)); + if ((result = tcgetattr(fd, ¤tState)) < 0) + { + DEBUG_WARN("tcgetattr failure, errno: %d", errno); + return result; + } + + if (memcmp(¤tState, termios_p, sizeof(struct termios)) != 0) + { + DEBUG_WARN("Failure: all parameters were not set on a second attempt."); + return -1; /* TMP: double-check whether some parameters can differ anyway */ + } + } + + return 0; +} + + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 0c6a85ea9..795bba0fc 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -24,6 +24,8 @@ #ifndef _WIN32 +#include + #include #include #include @@ -39,7 +41,57 @@ extern "C" { #endif -#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 +#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 +#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 + +/* #define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C */ +/* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */ +/* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */ +/* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */ +/* IOCTL_SERIAL_SET_CHARS 0x001B0058 */ +/* IOCTL_SERIAL_GET_CHARS 0x001B005C */ +/* IOCTL_SERIAL_SET_DTR 0x001B0024 */ +/* IOCTL_SERIAL_CLR_DTR 0x001B0028 */ +/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ +/* IOCTL_SERIAL_SET_RTS 0x001B0030 */ +/* IOCTL_SERIAL_CLR_RTS 0x001B0034 */ +/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ +/* IOCTL_SERIAL_SET_XON 0x001B003C */ +/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ +/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ +/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */ +/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */ +/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */ +/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */ +/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ +/* IOCTL_SERIAL_PURGE 0x001B004C */ +/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */ +/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */ +/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */ +/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ +/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ +#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 +/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ +/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ +/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */ +/* IOCTL_SERIAL_GET_STATS 0x001B008C */ +/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ +/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ +/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */ +/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */ + +/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */ +/* IOCTL_PAR_SET_INFORMATION 0x00160008 */ +/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */ +/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */ +/* IOCTL_IEEE1284_GET_MODE 0x00160014 */ +/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */ +/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */ +/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */ +/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */ +/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */ +/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ +/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ @@ -58,11 +110,14 @@ typedef struct _REMOTE_SERIAL_DRIVER { REMOTE_SERIAL_DRIVER_ID id; TCHAR *name; - BOOL (*set_baud_rate)(PSERIAL_BAUD_RATE pBaudRate); + BOOL (*set_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate /* in */); + BOOL (*get_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate /* out */); + BOOL (*get_properties)(WINPR_COMM *pComm, COMMPROP *pProperties /* out */); -} REMOTE_SERIAL_DRIVER, *PREMOTE_SERIAL_DRIVER; +} REMOTE_SERIAL_DRIVER; +int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 90f8ba5f0..97ef96bb5 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -20,26 +20,35 @@ * limitations under the License. */ +#ifndef _WIN32 + +#include "comm_sercx_sys.h" #include "comm_sercx2_sys.h" -#include "comm_serial_sys.h" /* specific functions only */ static REMOTE_SERIAL_DRIVER _SerCx2Sys = -{ +{ .id = RemoteSerialDriverSerCx2Sys, .name = _T("SerCx2.sys"), .set_baud_rate = NULL, + .get_baud_rate = NULL, + .get_properties = NULL, }; -PREMOTE_SERIAL_DRIVER SerCx2Sys() +REMOTE_SERIAL_DRIVER* SerCx2Sys_s() { - /* _SerCxSys completed with default SerialSys functions */ - PREMOTE_SERIAL_DRIVER serialSys = SerialSys(); + /* _SerCx2Sys completed with SerialSys or SerCxSys default functions */ + //REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); - _SerCx2Sys.set_baud_rate = serialSys->set_baud_rate; + _SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate; + _SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate; + _SerCx2Sys.get_properties = pSerCxSys->get_properties; return &_SerCx2Sys; } + +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.h b/winpr/libwinpr/comm/comm_sercx2_sys.h index c3aa53397..2d4be7655 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.h +++ b/winpr/libwinpr/comm/comm_sercx2_sys.h @@ -28,7 +28,7 @@ extern "C" { #endif -WINPR_API PREMOTE_SERIAL_DRIVER SerCx2Sys(); +REMOTE_SERIAL_DRIVER* SerCx2Sys_s(); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index d8072c604..85234789b 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -20,25 +20,250 @@ * limitations under the License. */ +#ifndef _WIN32 + +#include +#include + +#include #include "comm_serial_sys.h" + +/* 0: B* (Linux termios) + * 1: CBR_* or actual baud rate + * 2: BAUD_* (similar to SERIAL_BAUD_*) + */ +static const speed_t _SERCX_SYS_BAUD_TABLE[][3] = { +#ifdef B0 + {B0, 0, 0}, /* hang up */ +#endif +#ifdef B50 + {B50, 50, 0}, +#endif +#ifdef B75 + {B75, 75, BAUD_075}, +#endif +#ifdef B110 + {B110, CBR_110, BAUD_110}, +#endif +#ifdef B134 + {B134, 134, 0 /*BAUD_134_5*/}, +#endif +#ifdef B150 + {B150, 150, BAUD_150}, +#endif +#ifdef B200 + {B200, 200, 0}, +#endif +#ifdef B300 + {B300, CBR_300, BAUD_300}, +#endif +#ifdef B600 + {B600, CBR_600, BAUD_600}, +#endif +#ifdef B1200 + {B1200, CBR_1200, BAUD_1200}, +#endif +#ifdef B1800 + {B1800, 1800, BAUD_1800}, +#endif +#ifdef B2400 + {B2400, CBR_2400, BAUD_2400}, +#endif +#ifdef B4800 + {B4800, CBR_4800, BAUD_4800}, +#endif + /* {, ,BAUD_7200} */ +#ifdef B9600 + {B9600, CBR_9600, BAUD_9600}, +#endif + /* {, CBR_14400, BAUD_14400}, /\* unsupported on Linux *\/ */ +#ifdef B19200 + {B19200, CBR_19200, BAUD_19200}, +#endif +#ifdef B38400 + {B38400, CBR_38400, BAUD_38400}, +#endif + /* {, CBR_56000, BAUD_56K}, /\* unsupported on Linux *\/ */ +#ifdef B57600 + {B57600, CBR_57600, BAUD_57600}, +#endif +#ifdef B115200 + {B115200, CBR_115200, BAUD_115200}, +#endif + /* {, CBR_128000, BAUD_128K}, /\* unsupported on Linux *\/ */ + /* {, CBR_256000, BAUD_USER}, /\* unsupported on Linux *\/ */ +#ifdef B230400 + {B230400, 230400, BAUD_USER}, +#endif +#ifdef B460800 + {B460800, 460800, BAUD_USER}, +#endif +#ifdef B500000 + {B500000, 500000, BAUD_USER}, +#endif +#ifdef B576000 + {B576000, 576000, BAUD_USER}, +#endif +#ifdef B921600 + {B921600, 921600, BAUD_USER}, +#endif +#ifdef B1000000 + {B1000000, 1000000, BAUD_USER}, +#endif +#ifdef B1152000 + {B1152000, 1152000, BAUD_USER}, +#endif +#ifdef B1500000 + {B1500000, 1500000, BAUD_USER}, +#endif +#ifdef B2000000 + {B2000000, 2000000, BAUD_USER}, +#endif +#ifdef B2500000 + {B2500000, 2500000, BAUD_USER}, +#endif +#ifdef B3000000 + {B3000000, 3000000, BAUD_USER}, +#endif +#ifdef B3500000 + {B3500000, 3500000, BAUD_USER}, +#endif +#ifdef B4000000 + {B4000000, 4000000, BAUD_USER}, /* __MAX_BAUD */ +#endif +}; + + +static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) +{ + int i; + + // TMP: TODO: + + // TMP: required? + // ZeroMemory(pProperties, sizeof(COMMPROP); + + /* pProperties->PacketLength; */ + /* pProperties->PacketVersion; */ + /* pProperties->ServiceMask; */ + /* pProperties->Reserved1; */ + /* pProperties->MaxTxQueue; */ + /* pProperties->MaxRxQueue; */ + pProperties->dwMaxBaud = BAUD_USER; + /* pProperties->ProvSubType; */ + /* pProperties->ProvCapabilities; */ + /* pProperties->SettableParams; */ + + pProperties->dwSettableBaud = 0; + for (i=0; _SERCX_SYS_BAUD_TABLE[i][1]<=__MAX_BAUD; i++) + { + pProperties->dwSettableBaud |= _SERCX_SYS_BAUD_TABLE[i][2]; + } + + /* pProperties->SettableData; */ + /* pProperties->SettableStopParity; */ + /* pProperties->CurrentTxQueue; */ + /* pProperties->CurrentRxQueue; */ + /* pProperties->ProvSpec1; */ + /* pProperties->ProvSpec2; */ + /* pProperties->ProvChar[1]; */ + + return TRUE; +} + + +static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +{ + int i; + speed_t newSpeed; + struct termios futureState; + + ZeroMemory(&futureState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++) + { + if (_SERCX_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate) + { + newSpeed = _SERCX_SYS_BAUD_TABLE[i][0]; + if (cfsetspeed(&futureState, newSpeed) < 0) + { + DEBUG_WARN("failed to set speed 0x%x (%d)", newSpeed, pBaudRate->BaudRate); + return FALSE; + } + + assert(cfgetispeed(&futureState) == newSpeed); + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) + { + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + return FALSE; + } + + return TRUE; + } + } + + DEBUG_WARN("could not find a matching speed for the baud rate %d", pBaudRate->BaudRate); + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + + +static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +{ + int i; + speed_t currentSpeed; + struct termios currentState; + + ZeroMemory(¤tState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + currentSpeed = cfgetispeed(¤tState); + + for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++) + { + if (_SERCX_SYS_BAUD_TABLE[i][0] == currentSpeed) + { + pBaudRate->BaudRate = _SERCX_SYS_BAUD_TABLE[i][1]; + return TRUE; + } + } + + DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed); + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + + /* specific functions only */ static REMOTE_SERIAL_DRIVER _SerCxSys = { .id = RemoteSerialDriverSerCxSys, .name = _T("SerCx.sys"), - .set_baud_rate = NULL, + .set_baud_rate = _set_baud_rate, + .get_baud_rate = _get_baud_rate, + .get_properties = _get_properties, }; -PREMOTE_SERIAL_DRIVER SerCxSys() +REMOTE_SERIAL_DRIVER* SerCxSys_s() { /* _SerCxSys completed with default SerialSys functions */ - PREMOTE_SERIAL_DRIVER serialSys = SerialSys(); - - _SerCxSys.set_baud_rate = serialSys->set_baud_rate; + //REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys(); return &_SerCxSys; } + +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_sercx_sys.h b/winpr/libwinpr/comm/comm_sercx_sys.h index 1cceb29c8..d66c546ee 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.h +++ b/winpr/libwinpr/comm/comm_sercx_sys.h @@ -28,7 +28,7 @@ extern "C" { #endif -WINPR_API PREMOTE_SERIAL_DRIVER SerCxSys(); +REMOTE_SERIAL_DRIVER* SerCxSys_s(); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 3b55e1024..987268e37 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -20,11 +20,227 @@ * limitations under the License. */ +#ifndef _WIN32 + +#include + +#include + #include "comm_serial_sys.h" -static BOOL _set_baud_rate(PSERIAL_BAUD_RATE pBaudRate) -{ +#include +/* + * Linux, Windows speeds + * + */ +static const speed_t _SERIAL_SYS_BAUD_TABLE[][2] = { +#ifdef B0 + {B0, 0}, /* hang up */ +#endif +/* #ifdef B50 */ +/* {B50, }, /\* undefined by serial.sys *\/ */ +/* #endif */ +#ifdef B75 + {B75, SERIAL_BAUD_075}, +#endif +#ifdef B110 + {B110, SERIAL_BAUD_110}, +#endif +/* #ifdef B134 */ +/* {B134, SERIAL_BAUD_134_5}, /\* TODO: might be the same? *\/ */ +/* #endif */ +#ifdef B150 + {B150, SERIAL_BAUD_150}, +#endif +/* #ifdef B200 */ +/* {B200, }, /\* undefined by serial.sys *\/ */ +/* #endif */ +#ifdef B300 + {B300, SERIAL_BAUD_300}, +#endif +#ifdef B600 + {B600, SERIAL_BAUD_600}, +#endif +#ifdef B1200 + {B1200, SERIAL_BAUD_1200}, +#endif +#ifdef B1800 + {B1800, SERIAL_BAUD_1800}, +#endif +#ifdef B2400 + {B2400, SERIAL_BAUD_2400}, +#endif +#ifdef B4800 + {B4800, SERIAL_BAUD_4800}, +#endif + /* {, SERIAL_BAUD_7200} /\* undefined on Linux *\/ */ +#ifdef B9600 + {B9600, SERIAL_BAUD_9600}, +#endif + /* {, SERIAL_BAUD_14400} /\* undefined on Linux *\/ */ +#ifdef B19200 + {B19200, SERIAL_BAUD_19200}, +#endif +#ifdef B38400 + {B38400, SERIAL_BAUD_38400}, +#endif +/* {, SERIAL_BAUD_56K}, /\* undefined on Linux *\/ */ +#ifdef B57600 + {B57600, SERIAL_BAUD_57600}, +#endif + /* {, SERIAL_BAUD_128K} /\* undefined on Linux *\/ */ +#ifdef B115200 + {B115200, SERIAL_BAUD_115200}, /* _SERIAL_MAX_BAUD */ +#endif +/* undefined by serial.sys: +#ifdef B230400 + {B230400, }, +#endif +#ifdef B460800 + {B460800, }, +#endif +#ifdef B500000 + {B500000, }, +#endif +#ifdef B576000 + {B576000, }, +#endif +#ifdef B921600 + {B921600, }, +#endif +#ifdef B1000000 + {B1000000, }, +#endif +#ifdef B1152000 + {B1152000, }, +#endif +#ifdef B1500000 + {B1500000, }, +#endif +#ifdef B2000000 + {B2000000, }, +#endif +#ifdef B2500000 + {B2500000, }, +#endif +#ifdef B3000000 + {B3000000, }, +#endif +#ifdef B3500000 + {B3500000, }, +#endif +#ifdef B4000000 + {B4000000, }, __MAX_BAUD +#endif +*/ +}; + +#define _SERIAL_MAX_BAUD B115200 + +static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) +{ + int i; + + // TMP: TODO: + + // TMP: required? + // ZeroMemory(pProperties, sizeof(COMMPROP); + + /* pProperties->PacketLength; */ + /* pProperties->PacketVersion; */ + /* pProperties->ServiceMask; */ + /* pProperties->Reserved1; */ + /* pProperties->MaxTxQueue; */ + /* pProperties->MaxRxQueue; */ + pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */ + /* pProperties->ProvSubType; */ + /* pProperties->ProvCapabilities; */ + /* pProperties->SettableParams; */ + + pProperties->dwSettableBaud = 0; + for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++) + { + pProperties->dwSettableBaud |= _SERIAL_SYS_BAUD_TABLE[i][1]; + } + + /* pProperties->SettableData; */ + /* pProperties->SettableStopParity; */ + /* pProperties->CurrentTxQueue; */ + /* pProperties->CurrentRxQueue; */ + /* pProperties->ProvSpec1; */ + /* pProperties->ProvSpec2; */ + /* pProperties->ProvChar[1]; */ + + return TRUE; +} + +static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +{ + int i; + speed_t newSpeed; + struct termios futureState; + + ZeroMemory(&futureState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++) + { + if (_SERIAL_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate) + { + newSpeed = _SERIAL_SYS_BAUD_TABLE[i][0]; + if (cfsetspeed(&futureState, newSpeed) < 0) + { + DEBUG_WARN("failed to set speed %d (%d)", newSpeed, pBaudRate->BaudRate); + return FALSE; + } + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) + { + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + return FALSE; + } + + return TRUE; + } + } + + DEBUG_WARN("could not find a matching speed for the baud rate %d", pBaudRate->BaudRate); + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + + +static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +{ + int i; + speed_t currentSpeed; + struct termios currentState; + + ZeroMemory(¤tState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + currentSpeed = cfgetispeed(¤tState); + + for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++) + { + if (_SERIAL_SYS_BAUD_TABLE[i][0] == currentSpeed) + { + pBaudRate->BaudRate = _SERIAL_SYS_BAUD_TABLE[i][1]; + return TRUE; + } + } + + DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed); + SetLastError(ERROR_INVALID_DATA); return FALSE; } @@ -34,10 +250,14 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .id = RemoteSerialDriverSerialSys, .name = _T("Serial.sys"), .set_baud_rate = _set_baud_rate, + .get_baud_rate = _get_baud_rate, + .get_properties = _get_properties, }; -PREMOTE_SERIAL_DRIVER SerialSys() +REMOTE_SERIAL_DRIVER* SerialSys_s() { return &_SerialSys; } + +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.h b/winpr/libwinpr/comm/comm_serial_sys.h index a23238df5..0310d08bf 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.h +++ b/winpr/libwinpr/comm/comm_serial_sys.h @@ -28,7 +28,30 @@ extern "C" { #endif -WINPR_API PREMOTE_SERIAL_DRIVER SerialSys(); +/* Ntddser.h: http://msdn.microsoft.com/en-us/cc308432.aspx */ +#define SERIAL_BAUD_075 ((ULONG)0x00000001) +#define SERIAL_BAUD_110 ((ULONG)0x00000002) +#define SERIAL_BAUD_134_5 ((ULONG)0x00000004) +#define SERIAL_BAUD_150 ((ULONG)0x00000008) +#define SERIAL_BAUD_300 ((ULONG)0x00000010) +#define SERIAL_BAUD_600 ((ULONG)0x00000020) +#define SERIAL_BAUD_1200 ((ULONG)0x00000040) +#define SERIAL_BAUD_1800 ((ULONG)0x00000080) +#define SERIAL_BAUD_2400 ((ULONG)0x00000100) +#define SERIAL_BAUD_4800 ((ULONG)0x00000200) +#define SERIAL_BAUD_7200 ((ULONG)0x00000400) +#define SERIAL_BAUD_9600 ((ULONG)0x00000800) +#define SERIAL_BAUD_14400 ((ULONG)0x00001000) +#define SERIAL_BAUD_19200 ((ULONG)0x00002000) +#define SERIAL_BAUD_38400 ((ULONG)0x00004000) +#define SERIAL_BAUD_56K ((ULONG)0x00008000) +#define SERIAL_BAUD_128K ((ULONG)0x00010000) +#define SERIAL_BAUD_115200 ((ULONG)0x00020000) +#define SERIAL_BAUD_57600 ((ULONG)0x00040000) +#define SERIAL_BAUD_USER ((ULONG)0x10000000) + + +REMOTE_SERIAL_DRIVER* SerialSys_s(); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c index e4dcf99c7..832b0f22b 100644 --- a/winpr/libwinpr/comm/test/TestCommConfig.c +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -28,7 +28,7 @@ int TestCommConfig(int argc, char* argv[]) { DCB dcb; HANDLE hComm; - BOOL fSuccess; + BOOL success; LPCSTR lpFileName = "\\\\.\\COM1"; hComm = CreateFileA(lpFileName, @@ -41,8 +41,9 @@ int TestCommConfig(int argc, char* argv[]) return EXIT_FAILURE; } - fSuccess = DefineCommDevice(lpFileName, "/dev/null"); - if(!fSuccess) + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + success = DefineCommDevice(lpFileName, "/dev/ttyS0"); + if(!success) { printf("DefineCommDevice failure: %s\n", lpFileName); return EXIT_FAILURE; @@ -68,7 +69,7 @@ int TestCommConfig(int argc, char* argv[]) if (!hComm || (hComm == INVALID_HANDLE_VALUE)) { - printf("CreateFileA failure: %s\n", lpFileName); + printf("CreateFileA failure: %s GetLastError() = 0x%0.8x\n", lpFileName, GetLastError()); return EXIT_FAILURE; } @@ -76,11 +77,11 @@ int TestCommConfig(int argc, char* argv[]) * GetLastError should return ERROR_SHARING_VIOLATION */ ZeroMemory(&dcb, sizeof(DCB)); - - fSuccess = GetCommState(hComm, &dcb); - if (!fSuccess) + dcb.DCBlength = sizeof(DCB); + success = GetCommState(hComm, &dcb); + if (!success) { - printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError()); + printf("GetCommState failure: GetLastError() = Ox%x\n", (int) GetLastError()); return EXIT_FAILURE; } @@ -92,19 +93,19 @@ int TestCommConfig(int argc, char* argv[]) dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; - fSuccess = SetCommState(hComm, &dcb); + success = SetCommState(hComm, &dcb); - if (!fSuccess) + if (!success) { - printf("SetCommState failure: GetLastError() = %d\n", (int) GetLastError()); + printf("SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); return 0; } - fSuccess = GetCommState(hComm, &dcb); + success = GetCommState(hComm, &dcb); - if (!fSuccess) + if (!success) { - printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError()); + printf("GetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); return 0; } diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c index 83196e2ee..cb1f485e3 100644 --- a/winpr/libwinpr/comm/test/TestSetCommState.c +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -119,7 +119,6 @@ int TestSetCommState(int argc, char* argv[]) HANDLE hComm; // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail - result = DefineCommDevice("COM1", "/dev/ttyS0"); if (!result) { @@ -149,7 +148,7 @@ int TestSetCommState(int argc, char* argv[]) result = SetCommState(hComm, &dcb); if (!result) { - printf("SetCommState failure: 0x%x\n", GetLastError()); + printf("SetCommState failure: 0x%0.8x\n", GetLastError()); return EXIT_FAILURE; } From 18dd3d3141fb57715c2a1b4de0763cb87ead53d2 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 28 Apr 2014 22:32:27 +0200 Subject: [PATCH 11/61] winpr-comm: tests are done according the "remote serial driver" in TestGetCommState/TestSetCommState --- winpr/include/winpr/comm.h | 23 ++ winpr/libwinpr/comm/comm.c | 20 ++ winpr/libwinpr/comm/comm.h | 5 +- winpr/libwinpr/comm/comm_serial_sys.h | 23 -- winpr/libwinpr/comm/test/TestGetCommState.c | 85 +++-- winpr/libwinpr/comm/test/TestSetCommState.c | 324 +++++++++++++++----- 6 files changed, 355 insertions(+), 125 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 8b87743dc..804b8da51 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -171,6 +171,29 @@ #define BAUD_57600 ((DWORD)0x00040000) #define BAUD_USER ((DWORD)0x10000000) +/* Ntddser.h: http://msdn.microsoft.com/en-us/cc308432.aspx */ +#define SERIAL_BAUD_075 ((ULONG)0x00000001) +#define SERIAL_BAUD_110 ((ULONG)0x00000002) +#define SERIAL_BAUD_134_5 ((ULONG)0x00000004) +#define SERIAL_BAUD_150 ((ULONG)0x00000008) +#define SERIAL_BAUD_300 ((ULONG)0x00000010) +#define SERIAL_BAUD_600 ((ULONG)0x00000020) +#define SERIAL_BAUD_1200 ((ULONG)0x00000040) +#define SERIAL_BAUD_1800 ((ULONG)0x00000080) +#define SERIAL_BAUD_2400 ((ULONG)0x00000100) +#define SERIAL_BAUD_4800 ((ULONG)0x00000200) +#define SERIAL_BAUD_7200 ((ULONG)0x00000400) +#define SERIAL_BAUD_9600 ((ULONG)0x00000800) +#define SERIAL_BAUD_14400 ((ULONG)0x00001000) +#define SERIAL_BAUD_19200 ((ULONG)0x00002000) +#define SERIAL_BAUD_38400 ((ULONG)0x00004000) +#define SERIAL_BAUD_56K ((ULONG)0x00008000) +#define SERIAL_BAUD_128K ((ULONG)0x00010000) +#define SERIAL_BAUD_115200 ((ULONG)0x00020000) +#define SERIAL_BAUD_57600 ((ULONG)0x00040000) +#define SERIAL_BAUD_USER ((ULONG)0x10000000) + + #define DATABITS_5 ((WORD)0x0001) #define DATABITS_6 ((WORD)0x0002) #define DATABITS_7 ((WORD)0x0004) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index c810d6863..a477df734 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -675,6 +675,26 @@ BOOL IsCommDevice(LPCTSTR lpDeviceName) } +/** + * Sets + */ +void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID driverId) +{ + ULONG Type; + PVOID Object; + WINPR_COMM* pComm; + + if (!winpr_Handle_GetInfo(hComm, &Type, &Object)) + { + DEBUG_WARN("_comm_setRemoteSerialDriver failure"); + return; + } + + pComm = (WINPR_COMM*)Object; + pComm->remoteSerialDriverId = driverId; +} + + /** * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363198%28v=vs.85%29.aspx * diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index c9f121442..f77dad7e7 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -36,7 +36,7 @@ typedef enum _REMOTE_SERIAL_DRIVER_ID RemoteSerialDriverUnknown = 0, RemoteSerialDriverSerialSys, RemoteSerialDriverSerCxSys, - RemoteSerialDriverSerCx2Sys /* default fallback */ + RemoteSerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */ } REMOTE_SERIAL_DRIVER_ID; struct winpr_comm @@ -48,8 +48,11 @@ struct winpr_comm /* NB: CloseHandle() has to free resources */ }; + typedef struct winpr_comm WINPR_COMM; +void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.h b/winpr/libwinpr/comm/comm_serial_sys.h index 0310d08bf..ec5f7847f 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.h +++ b/winpr/libwinpr/comm/comm_serial_sys.h @@ -28,29 +28,6 @@ extern "C" { #endif -/* Ntddser.h: http://msdn.microsoft.com/en-us/cc308432.aspx */ -#define SERIAL_BAUD_075 ((ULONG)0x00000001) -#define SERIAL_BAUD_110 ((ULONG)0x00000002) -#define SERIAL_BAUD_134_5 ((ULONG)0x00000004) -#define SERIAL_BAUD_150 ((ULONG)0x00000008) -#define SERIAL_BAUD_300 ((ULONG)0x00000010) -#define SERIAL_BAUD_600 ((ULONG)0x00000020) -#define SERIAL_BAUD_1200 ((ULONG)0x00000040) -#define SERIAL_BAUD_1800 ((ULONG)0x00000080) -#define SERIAL_BAUD_2400 ((ULONG)0x00000100) -#define SERIAL_BAUD_4800 ((ULONG)0x00000200) -#define SERIAL_BAUD_7200 ((ULONG)0x00000400) -#define SERIAL_BAUD_9600 ((ULONG)0x00000800) -#define SERIAL_BAUD_14400 ((ULONG)0x00001000) -#define SERIAL_BAUD_19200 ((ULONG)0x00002000) -#define SERIAL_BAUD_38400 ((ULONG)0x00004000) -#define SERIAL_BAUD_56K ((ULONG)0x00008000) -#define SERIAL_BAUD_128K ((ULONG)0x00010000) -#define SERIAL_BAUD_115200 ((ULONG)0x00020000) -#define SERIAL_BAUD_57600 ((ULONG)0x00040000) -#define SERIAL_BAUD_USER ((ULONG)0x10000000) - - REMOTE_SERIAL_DRIVER* SerialSys_s(); #ifdef __cplusplus diff --git a/winpr/libwinpr/comm/test/TestGetCommState.c b/winpr/libwinpr/comm/test/TestGetCommState.c index df78215b1..ceb9026c7 100644 --- a/winpr/libwinpr/comm/test/TestGetCommState.c +++ b/winpr/libwinpr/comm/test/TestGetCommState.c @@ -22,14 +22,60 @@ #include #include -int TestGetCommState(int argc, char* argv[]) +#include "../comm.h" + +static BOOL test_generic(HANDLE hComm) { DCB dcb, *pDcb; BOOL result; + + 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(1, sizeof(DCB) * 2); + 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[]) +{ + BOOL result; HANDLE hComm; // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail - result = DefineCommDevice("COM1", "/dev/ttyS0"); if (!result) { @@ -46,41 +92,30 @@ int TestGetCommState(int argc, char* argv[]) return EXIT_FAILURE; } - ZeroMemory(&dcb, sizeof(dcb)); - result = GetCommState(hComm, &dcb); - if (result) + if (!test_generic(hComm)) { - printf("GetCommState failure, should have returned false because dcb.DCBlength has been let uninitialized\n"); + printf("test_generic failure (RemoteSerialDriverUnknown)\n"); return EXIT_FAILURE; } - - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(DCB) / 2; /* improper value */ - result = GetCommState(hComm, &dcb); - if (result) + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + if (!test_generic(hComm)) { - printf("GetCommState failure, should have return false because dcb.DCBlength was not correctly initialized\n"); + printf("test_generic failure (RemoteSerialDriverSerialSys)\n"); return EXIT_FAILURE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(DCB); - result = GetCommState(hComm, &dcb); - if (!result) + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + if (!test_generic(hComm)) { - printf("GetCommState failure: Ox%x, with adjusted DCBlength\n", GetLastError()); + printf("test_generic failure (RemoteSerialDriverSerCxSys)\n"); return EXIT_FAILURE; } - - pDcb = (DCB*)calloc(1, sizeof(DCB) * 2); - pDcb->DCBlength = sizeof(DCB) * 2; - result = GetCommState(hComm, pDcb); - result = result && (pDcb->DCBlength == sizeof(DCB) * 2); - free(pDcb); - if (!result) + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + if (!test_generic(hComm)) { - printf("GetCommState failure: 0x%x, with bigger DCBlength\n", GetLastError()); + printf("test_generic failure (RemoteSerialDriverSerCx2Sys)\n"); return EXIT_FAILURE; } diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c index cb1f485e3..48854ae49 100644 --- a/winpr/libwinpr/comm/test/TestSetCommState.c +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -22,8 +22,9 @@ #include #include +#include "../comm.h" -static int test_fParity(HANDLE hComm) +static BOOL test_fParity(HANDLE hComm) { DCB dcb; BOOL result; @@ -33,8 +34,8 @@ static int test_fParity(HANDLE hComm) result = GetCommState(hComm, &dcb); if (!result) { - printf("GetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } /* test 1 */ @@ -42,8 +43,8 @@ static int test_fParity(HANDLE hComm) result = SetCommState(hComm, &dcb); if (!result) { - printf("SetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } ZeroMemory(&dcb, sizeof(dcb)); @@ -51,14 +52,14 @@ static int test_fParity(HANDLE hComm) result = GetCommState(hComm, &dcb); if (!result) { - printf("GetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } if (!dcb.fParity) { - printf("unexpected fParity: %d instead of TRUE\n", dcb.fParity); - return EXIT_FAILURE; + fprintf(stderr, "unexpected fParity: %d instead of TRUE\n", dcb.fParity); + return FALSE; } /* test 2 */ @@ -66,8 +67,8 @@ static int test_fParity(HANDLE hComm) result = SetCommState(hComm, &dcb); if (!result) { - printf("SetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } ZeroMemory(&dcb, sizeof(dcb)); @@ -75,14 +76,14 @@ static int test_fParity(HANDLE hComm) result = GetCommState(hComm, &dcb); if (!result) { - printf("GetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } if (dcb.fParity) { - printf("unexpected fParity: %d instead of FALSE\n", dcb.fParity); - return EXIT_FAILURE; + fprintf(stderr, "unexpected fParity: %d instead of FALSE\n", dcb.fParity); + return FALSE; } /* test 3 (redo test 1) */ @@ -90,8 +91,8 @@ static int test_fParity(HANDLE hComm) result = SetCommState(hComm, &dcb); if (!result) { - printf("SetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } ZeroMemory(&dcb, sizeof(dcb)); @@ -99,22 +100,225 @@ static int test_fParity(HANDLE hComm) result = GetCommState(hComm, &dcb); if (!result) { - printf("GetCommState failure: 0x%x\n", GetLastError()); - return EXIT_FAILURE; + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; } if (!dcb.fParity) { - printf("unexpected fParity: %d instead of TRUE\n", dcb.fParity); - return EXIT_FAILURE; + fprintf(stderr, "unexpected fParity: %d instead of TRUE\n", dcb.fParity); + return FALSE; } - return EXIT_SUCCESS; + return TRUE; +} + + +static BOOL test_SerialSys(HANDLE hComm) +{ + DCB dcb; + BOOL result; + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + /* Test 1 */ + dcb.BaudRate = SERIAL_BAUD_115200; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + if (dcb.BaudRate != SERIAL_BAUD_115200) + { + fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (SERIAL_BAUD_115200)\n", SERIAL_BAUD_115200); + return FALSE; + } + + /* Test 2 using a defferent baud rate */ + + dcb.BaudRate = SERIAL_BAUD_57600; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + if (dcb.BaudRate != SERIAL_BAUD_57600) + { + fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (SERIAL_BAUD_57600)\n", SERIAL_BAUD_57600); + return FALSE; + } + + /* Test 3 using an unsupported baud rate on Linux */ + dcb.BaudRate = SERIAL_BAUD_128K; + result = SetCommState(hComm, &dcb); + if (result) + { + fprintf(stderr, "SetCommState failure: unexpected support of BaudRate=%d (SERIAL_BAUD_128K)\n", SERIAL_BAUD_128K); + return FALSE; + } + + return TRUE; +} + +static BOOL test_SerCxSys(HANDLE hComm) +{ + DCB dcb; + BOOL result; + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + /* Test 1 */ + dcb.BaudRate = CBR_115200; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + if (dcb.BaudRate != CBR_115200) + { + fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_115200)\n", CBR_115200); + return FALSE; + } + + /* Test 2 using a defferent baud rate */ + + dcb.BaudRate = CBR_57600; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + if (dcb.BaudRate != CBR_57600) + { + 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) + { + fprintf(stderr, "SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n", CBR_128000); + return FALSE; + } + + return TRUE; +} + + +static BOOL test_SerCx2Sys(HANDLE hComm) +{ + /* as of today there is no difference */ + return test_SerCxSys(hComm); +} + +static BOOL test_generic(HANDLE hComm) +{ + DCB dcb, dcb2; + BOOL result; + + ZeroMemory(&dcb, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + 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) + { + fprintf(stderr, "SetCommState failure: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + if (memcmp(&dcb, &dcb2, sizeof(DCB)) != 0) + { + 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)) + { + fprintf(stderr, "test_fParity failure\n"); + return FALSE; + } + + return TRUE; } int TestSetCommState(int argc, char* argv[]) { - DCB dcb, *pDcb; BOOL result; HANDLE hComm; @@ -122,7 +326,7 @@ int TestSetCommState(int argc, char* argv[]) result = DefineCommDevice("COM1", "/dev/ttyS0"); if (!result) { - printf("DefineCommDevice failure: 0x%x\n", GetLastError()); + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); return EXIT_FAILURE; } @@ -131,84 +335,52 @@ int TestSetCommState(int argc, char* argv[]) 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { - printf("CreateFileA failure: 0x%x\n", GetLastError()); + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); return EXIT_FAILURE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); - result = GetCommState(hComm, &dcb); - if (!result) + if (!test_generic(hComm)) { - printf("GetCommState failure: 0x%x\n", GetLastError()); + fprintf(stderr, "test_generic failure (RemoteSerialDriverUnknown)\n"); return EXIT_FAILURE; } - dcb.BaudRate = CBR_115200; - result = SetCommState(hComm, &dcb); - if (!result) + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + if (!test_generic(hComm)) { - printf("SetCommState failure: 0x%0.8x\n", GetLastError()); + fprintf(stderr, "test_generic failure (RemoteSerialDriverSerialSys)\n"); return EXIT_FAILURE; } - - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); - result = GetCommState(hComm, &dcb); - if (!result) + if (!test_SerialSys(hComm)) { - printf("GetCommState failure: 0x%x\n", GetLastError()); + fprintf(stderr, "test_SerialSys failure\n"); return EXIT_FAILURE; } - if (dcb.BaudRate != CBR_115200) + + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + if (!test_generic(hComm)) { - printf("SetCommState failure: could not set BaudRate=%d (CBR_115200)\n", CBR_115200); + fprintf(stderr, "test_generic failure (RemoteSerialDriverSerCxSys)\n"); return EXIT_FAILURE; } - - - /* Test 2 using a defferent baud rate */ - - dcb.BaudRate = CBR_57600; - result = SetCommState(hComm, &dcb); - if (!result) + if (!test_SerCxSys(hComm)) { - printf("SetCommState failure: 0x%x\n", GetLastError()); + fprintf(stderr, "test_SerCxSys failure\n"); return EXIT_FAILURE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); - result = GetCommState(hComm, &dcb); - if (!result) + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + if (!test_generic(hComm)) { - printf("GetCommState failure: 0x%x\n", GetLastError()); + fprintf(stderr, "test_generic failure (RemoteSerialDriverSerCx2Sys)\n"); return EXIT_FAILURE; } - if (dcb.BaudRate != CBR_57600) + if (!test_SerCx2Sys(hComm)) { - printf("SetCommState failure: could not set BaudRate=%d (CBR_57600)\n", CBR_57600); + fprintf(stderr, "test_SerCx2Sys failure\n"); return EXIT_FAILURE; } - /* Test 3 using an unsupported baud rate on Linux */ -#ifdef __linux__ - dcb.BaudRate = CBR_128000; - result = SetCommState(hComm, &dcb); - if (result) - { - printf("SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n", CBR_128000); - return EXIT_FAILURE; - } -#endif /* __linux__ */ - - // TODO: a more complete and generic test using GetCommProperties() - - /* TMP: TODO: fBinary tests */ - - /* fParity tests */ - if (test_fParity(hComm) != EXIT_SUCCESS) - return EXIT_FAILURE; - return EXIT_SUCCESS; } From fff1f22f8cf167404a99ede650d6d4824da14386 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 28 Apr 2014 22:56:25 +0200 Subject: [PATCH 12/61] winpr-comm: completed GetCommProperties() (the underlying ioctl remains unfinished) --- winpr/libwinpr/comm/comm.c | 16 ++++++++- winpr/libwinpr/comm/comm_sercx_sys.c | 2 +- winpr/libwinpr/comm/test/TestCommConfig.c | 44 +++++++++++++++++------ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index a477df734..7c87aae93 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -131,12 +131,26 @@ BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat) return TRUE; } +/** + * ERRORS: + * ERROR_INVALID_HANDLE + */ BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp) { WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; - if (!pComm) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, lpCommProp, sizeof(COMMPROP), &bytesReturned, NULL)) + { + DEBUG_WARN("GetCommProperties failure."); + return FALSE; + } return TRUE; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 85234789b..70f0fba99 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -157,7 +157,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) /* pProperties->SettableParams; */ pProperties->dwSettableBaud = 0; - for (i=0; _SERCX_SYS_BAUD_TABLE[i][1]<=__MAX_BAUD; i++) + for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++) { pProperties->dwSettableBaud |= _SERCX_SYS_BAUD_TABLE[i][2]; } diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c index 832b0f22b..f8953d21b 100644 --- a/winpr/libwinpr/comm/test/TestCommConfig.c +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -30,6 +30,7 @@ int TestCommConfig(int argc, char* argv[]) HANDLE hComm; BOOL success; LPCSTR lpFileName = "\\\\.\\COM1"; + COMMPROP commProp; hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, @@ -37,7 +38,7 @@ int TestCommConfig(int argc, char* argv[]) if (hComm && (hComm != INVALID_HANDLE_VALUE)) { - printf("CreateFileA failure: could create a handle on a not yet defined device: %s\n", lpFileName); + fprintf(stderr, "CreateFileA failure: could create a handle on a not yet defined device: %s\n", lpFileName); return EXIT_FAILURE; } @@ -45,7 +46,7 @@ int TestCommConfig(int argc, char* argv[]) success = DefineCommDevice(lpFileName, "/dev/ttyS0"); if(!success) { - printf("DefineCommDevice failure: %s\n", lpFileName); + fprintf(stderr, "DefineCommDevice failure: %s\n", lpFileName); return EXIT_FAILURE; } @@ -58,7 +59,7 @@ int TestCommConfig(int argc, char* argv[]) (HANDLE)1234); /* invalid parmaeter */ if (hComm != INVALID_HANDLE_VALUE) { - printf("CreateFileA failure: could create a handle with some invalid parameters %s\n", lpFileName); + fprintf(stderr, "CreateFileA failure: could create a handle with some invalid parameters %s\n", lpFileName); return EXIT_FAILURE; } @@ -69,7 +70,7 @@ int TestCommConfig(int argc, char* argv[]) if (!hComm || (hComm == INVALID_HANDLE_VALUE)) { - printf("CreateFileA failure: %s GetLastError() = 0x%0.8x\n", lpFileName, GetLastError()); + fprintf(stderr, "CreateFileA failure: %s GetLastError() = 0x%0.8x\n", lpFileName, GetLastError()); return EXIT_FAILURE; } @@ -81,12 +82,33 @@ int TestCommConfig(int argc, char* argv[]) success = GetCommState(hComm, &dcb); if (!success) { - printf("GetCommState failure: GetLastError() = Ox%x\n", (int) GetLastError()); + fprintf(stderr, "GetCommState failure: GetLastError() = Ox%x\n", (int) GetLastError()); return EXIT_FAILURE; } - printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", - (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + fprintf(stderr, "BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + + ZeroMemory(&commProp, sizeof(COMMPROP)); + if (!GetCommProperties(hComm, &commProp)) + { + fprintf(stderr, "GetCommProperties failure: GetLastError(): 0x0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + + if ((commProp.dwSettableBaud & BAUD_57600) <= 0) + { + fprintf(stderr, "BAUD_57600 unsupported!\n"); + return EXIT_FAILURE; + } + + if ((commProp.dwSettableBaud & BAUD_14400) > 0) + { + fprintf(stderr, "BAUD_14400 supported!\n"); + return EXIT_FAILURE; + } + + /* TODO: */ dcb.BaudRate = CBR_57600; dcb.ByteSize = 8; @@ -97,7 +119,7 @@ int TestCommConfig(int argc, char* argv[]) if (!success) { - printf("SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); + fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); return 0; } @@ -105,12 +127,12 @@ int TestCommConfig(int argc, char* argv[]) if (!success) { - printf("GetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); + fprintf(stderr, "GetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); return 0; } - printf("BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", - (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + fprintf(stderr, "BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); CloseHandle(hComm); From ee2339addca23ac0d2b215ab1ff5abd30225283a Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 29 Apr 2014 04:04:09 +0200 Subject: [PATCH 13/61] winpr-comm: implemented IOCTL_SERIAL_SET_CHARS and IOCTL_SERIAL_GET_CHARS --- channels/serial/client/serial_main.c | 4 + winpr/libwinpr/comm/comm.c | 46 +++++- winpr/libwinpr/comm/comm_ioctl.c | 36 +++++ winpr/libwinpr/comm/comm_ioctl.h | 26 +++- winpr/libwinpr/comm/comm_sercx2_sys.c | 42 ++++- winpr/libwinpr/comm/comm_sercx_sys.c | 21 ++- winpr/libwinpr/comm/comm_serial_sys.c | 160 ++++++++++++++++++-- winpr/libwinpr/comm/test/CMakeLists.txt | 1 + winpr/libwinpr/comm/test/TestGetCommState.c | 12 +- winpr/libwinpr/comm/test/TestSerialChars.c | 154 +++++++++++++++++++ winpr/libwinpr/comm/test/TestSetCommState.c | 47 +++--- 11 files changed, 489 insertions(+), 60 deletions(-) create mode 100644 winpr/libwinpr/comm/test/TestSerialChars.c diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index a848250c6..5285aa854 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -305,6 +305,10 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_BUFFER_TOO_SMALL; /* TMP: better have STATUS_BUFFER_SIZE_TOO_SMALL? http://msdn.microsoft.com/en-us/library/windows/hardware/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */ break; + case ERROR_INVALID_PARAMETER: + irp->IoStatus = STATUS_INVALID_PARAMETER; + break; + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 7c87aae93..e09789342 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -218,8 +218,29 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) lpLocalDcb->fBinary = TRUE; /* TMP: TODO: seems equivalent to the raw mode */ - lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; + lpLocalDcb->fParity = (currentState.c_cflag & PARENB) != 0; + /* TMP: TODO: */ + /* (...) */ + + + + SERIAL_CHARS serialChars; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) + { + DEBUG_WARN("GetCommState failure: could not get the serial chars."); + goto error_handle; + } + + lpLocalDcb->XonChar = serialChars.XonChar; + + lpLocalDcb->XoffChar = serialChars.XoffChar; + + lpLocalDcb->ErrorChar = serialChars.ErrorChar; + + lpLocalDcb->EofChar = serialChars.EofChar; + + lpLocalDcb->EvtChar = serialChars.EventChar; memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength); @@ -278,6 +299,22 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) return FALSE; } + SERIAL_CHARS serialChars; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) + { + DEBUG_WARN("SetCommState failure: could not get the initial serial chars."); + return FALSE; + } + serialChars.XonChar = lpDCB->XonChar; + serialChars.XoffChar = lpDCB->XoffChar; + serialChars.ErrorChar = lpDCB->ErrorChar; + serialChars.EofChar = lpDCB->EofChar; + serialChars.EventChar = lpDCB->EvtChar; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars, sizeof(SERIAL_CHARS), NULL, 0, &bytesReturned, NULL)) + { + DEBUG_WARN("SetCommState failure: could not set the serial chars."); + return FALSE; + } /** upcomingTermios stage **/ @@ -300,13 +337,16 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) if (lpDCB->fParity) { - upcomingTermios.c_iflag |= INPCK; + upcomingTermios.c_cflag |= PARENB; } else { - upcomingTermios.c_iflag &= ~INPCK; + upcomingTermios.c_cflag &= ~PARENB; } + // TMP: TODO: + // (...) + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx * * The SetCommState function reconfigures the communications diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index a5916e9e7..9524ee73c 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -176,6 +176,42 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe return TRUE; } } + case IOCTL_SERIAL_SET_CHARS: + { + if (pRemoteSerialDriver->set_serial_chars) + { + SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_CHARS)); + if (nInBufferSize < sizeof(SERIAL_CHARS)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + return pRemoteSerialDriver->set_serial_chars(pComm, pSerialChars); + } + } + case IOCTL_SERIAL_GET_CHARS: + { + if (pRemoteSerialDriver->get_serial_chars) + { + SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_CHARS)); + if (nOutBufferSize < sizeof(SERIAL_CHARS)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_serial_chars(pComm, pSerialChars)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_CHARS); + return TRUE; + } + } } DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 795bba0fc..593dd5b5f 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -48,8 +48,11 @@ extern "C" { /* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */ /* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */ /* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */ -/* IOCTL_SERIAL_SET_CHARS 0x001B0058 */ -/* IOCTL_SERIAL_GET_CHARS 0x001B005C */ + +/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ +#define IOCTL_SERIAL_GET_CHARS 0x001B0058 +#define IOCTL_SERIAL_SET_CHARS 0x001B005C + /* IOCTL_SERIAL_SET_DTR 0x001B0024 */ /* IOCTL_SERIAL_CLR_DTR 0x001B0028 */ /* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ @@ -101,6 +104,17 @@ typedef struct _SERIAL_BAUD_RATE } SERIAL_BAUD_RATE, *PSERIAL_BAUD_RATE; +typedef struct _SERIAL_CHARS +{ + UCHAR EofChar; + UCHAR ErrorChar; + UCHAR BreakChar; + UCHAR EventChar; + UCHAR XonChar; + UCHAR XoffChar; +} SERIAL_CHARS, *PSERIAL_CHARS; + + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -110,9 +124,11 @@ typedef struct _REMOTE_SERIAL_DRIVER { REMOTE_SERIAL_DRIVER_ID id; TCHAR *name; - BOOL (*set_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate /* in */); - BOOL (*get_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate /* out */); - BOOL (*get_properties)(WINPR_COMM *pComm, COMMPROP *pProperties /* out */); + 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 97ef96bb5..99bf8fe78 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -27,14 +27,40 @@ #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_COMM* pComm, const SERIAL_CHARS* pSerialChars) +{ + return TRUE; +} + + +static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars) +{ + ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS)); + return TRUE; +} + + /* specific functions only */ static REMOTE_SERIAL_DRIVER _SerCx2Sys = { - .id = RemoteSerialDriverSerCx2Sys, - .name = _T("SerCx2.sys"), - .set_baud_rate = NULL, - .get_baud_rate = NULL, - .get_properties = NULL, + .id = RemoteSerialDriverSerCx2Sys, + .name = _T("SerCx2.sys"), + .set_baud_rate = NULL, + .get_baud_rate = NULL, + .get_properties = NULL, + .set_serial_chars = _set_serial_chars, + .get_serial_chars = _get_serial_chars, }; @@ -44,9 +70,9 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() //REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); - _SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate; - _SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate; - _SerCx2Sys.get_properties = pSerCxSys->get_properties; + _SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate; + _SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate; + _SerCx2Sys.get_properties = pSerCxSys->get_properties; return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 70f0fba99..bd4523bd4 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -174,7 +174,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) } -static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) { int i; speed_t newSpeed; @@ -249,19 +249,24 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) /* specific functions only */ static REMOTE_SERIAL_DRIVER _SerCxSys = { - .id = RemoteSerialDriverSerCxSys, - .name = _T("SerCx.sys"), - .set_baud_rate = _set_baud_rate, - .get_baud_rate = _get_baud_rate, - .get_properties = _get_properties, + .id = RemoteSerialDriverSerCxSys, + .name = _T("SerCx.sys"), + .set_baud_rate = _set_baud_rate, + .get_baud_rate = _get_baud_rate, + .get_properties = _get_properties, + .set_serial_chars = NULL, + .get_serial_chars = NULL, }; REMOTE_SERIAL_DRIVER* SerCxSys_s() { - /* _SerCxSys completed with default SerialSys functions */ - //REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys(); + /* _SerCxSys completed with default SerialSys_s functions */ + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + _SerCxSys.set_serial_chars = pSerialSys->set_serial_chars; + _SerCxSys.get_serial_chars = pSerialSys->get_serial_chars; return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 987268e37..315bf7e8f 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -175,14 +175,14 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) return TRUE; } -static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) { int i; speed_t newSpeed; - struct termios futureState; + struct termios upcomingTermios; - ZeroMemory(&futureState, sizeof(struct termios)); - if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) { SetLastError(ERROR_IO_DEVICE); return FALSE; @@ -193,13 +193,13 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) if (_SERIAL_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate) { newSpeed = _SERIAL_SYS_BAUD_TABLE[i][0]; - if (cfsetspeed(&futureState, newSpeed) < 0) + if (cfsetspeed(&upcomingTermios, newSpeed) < 0) { DEBUG_WARN("failed to set speed %d (%d)", newSpeed, pBaudRate->BaudRate); return FALSE; } - if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); return FALSE; @@ -244,14 +244,152 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) return FALSE; } +/** + * NOTE: Only XonChar and XoffChar are plenty supported with Linux + * N_TTY line discipline. + * + * ERRORS: + * ERROR_IO_DEVICE + * ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same; + */ +static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChars) +{ + struct termios upcomingTermios; + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (pSerialChars->XonChar == pSerialChars->XoffChar) + { + /* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546688%28v=vs.85%29.aspx */ + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* termios(3): (..) above symbolic subscript values are all + * different, except that VTIME, VMIN may have the same value + * as VEOL, VEOF, respectively. In noncanonical mode the + * special character meaning is replaced by the timeout + * meaning. + * + * It doesn't seem the case of the Linux's implementation but + * in our context, the cannonical mode (fBinary=FALSE) should + * never be enabled. + */ + + if (upcomingTermios.c_lflag & ICANON) + { + upcomingTermios.c_cc[VEOF] = pSerialChars->EofChar; + DEBUG_WARN("c_cc[VEOF] is not supposed to be modified!"); + } + /* else let c_cc[VEOF] unchanged */ + + + /* According the Linux's n_tty discipline, charaters with a + * parity error can only be let unchanged, replaced by \0 or + * get the prefix the prefix \377 \0 + */ + + if (pSerialChars->ErrorChar == '\0') + { + /* Also suppose PARENB !IGNPAR !PARMRK to be effective */ + upcomingTermios.c_iflag |= INPCK; + } + else + { + /* FIXME: develop a line discipline dedicated to the + * RDP redirection. Erroneous characters might also be + * caught during read/write operations? + */ + DEBUG_WARN("ErrorChar='%c' cannot be set, characters with a parity error will be let unchanged.\n", pSerialChars->ErrorChar); + } + + if (pSerialChars->BreakChar == '\0') + { + upcomingTermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK); + } + else + { + /* FIXME: develop a line discipline dedicated to the + * RDP redirection. Break characters might also be + * caught during read/write operations? + */ + DEBUG_WARN("BreakChar='%c' cannot be set.\n", pSerialChars->ErrorChar); + } + + /* FIXME: Didn't find anything similar inside N_TTY. Develop a + * line discipline dedicated to the RDP redirection. + */ + DEBUG_WARN("EventChar='%c' cannot be set\n", pSerialChars->EventChar); + + upcomingTermios.c_cc[VSTART] = pSerialChars->XonChar; + + upcomingTermios.c_cc[VSTOP] = pSerialChars->XoffChar; + + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + return FALSE; + } + + return TRUE; +} + + +static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS)); + + if (currentTermios.c_lflag & ICANON) + { + pSerialChars->EofChar = currentTermios.c_cc[VEOF]; + } + + /* FIXME: see also: _set_serial_chars() */ + if (currentTermios.c_iflag & INPCK) + pSerialChars->ErrorChar = '\0'; + /* else '\0' is currently used anyway */ + + /* FIXME: see also: _set_serial_chars() */ + if (currentTermios.c_iflag & ~IGNBRK & BRKINT) + pSerialChars->BreakChar = '\0'; + /* else '\0' is currently used anyway */ + + /* FIXME: see also: _set_serial_chars() */ + pSerialChars->EventChar = '\0'; + + pSerialChars->XonChar = currentTermios.c_cc[VSTART]; + + pSerialChars->XoffChar = currentTermios.c_cc[VSTOP]; + + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { - .id = RemoteSerialDriverSerialSys, - .name = _T("Serial.sys"), - .set_baud_rate = _set_baud_rate, - .get_baud_rate = _get_baud_rate, - .get_properties = _get_properties, + .id = RemoteSerialDriverSerialSys, + .name = _T("Serial.sys"), + .set_baud_rate = _set_baud_rate, + .get_baud_rate = _get_baud_rate, + .get_properties = _get_properties, + .set_serial_chars = _set_serial_chars, + .get_serial_chars = _get_serial_chars, }; diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt index bc9bfaa8c..cad34b38d 100644 --- a/winpr/libwinpr/comm/test/CMakeLists.txt +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -9,6 +9,7 @@ set(${MODULE_PREFIX}_TESTS TestCommConfig.c TestGetCommState.c TestSetCommState.c + TestSerialChars.c TestCommMonitor.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/comm/test/TestGetCommState.c b/winpr/libwinpr/comm/test/TestGetCommState.c index ceb9026c7..ab2d1f441 100644 --- a/winpr/libwinpr/comm/test/TestGetCommState.c +++ b/winpr/libwinpr/comm/test/TestGetCommState.c @@ -29,7 +29,7 @@ static BOOL test_generic(HANDLE hComm) DCB dcb, *pDcb; BOOL result; - ZeroMemory(&dcb, sizeof(dcb)); + ZeroMemory(&dcb, sizeof(DCB)); result = GetCommState(hComm, &dcb); if (result) { @@ -38,7 +38,7 @@ static BOOL test_generic(HANDLE hComm) } - ZeroMemory(&dcb, sizeof(dcb)); + ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB) / 2; /* improper value */ result = GetCommState(hComm, &dcb); if (result) @@ -47,7 +47,7 @@ static BOOL test_generic(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); + ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); result = GetCommState(hComm, &dcb); if (!result) @@ -119,5 +119,11 @@ int TestGetCommState(int argc, char* argv[]) return EXIT_FAILURE; } + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } diff --git a/winpr/libwinpr/comm/test/TestSerialChars.c b/winpr/libwinpr/comm/test/TestSerialChars.c new file mode 100644 index 000000000..4937b60e2 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestSerialChars.c @@ -0,0 +1,154 @@ +/** + * 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 + +#include +#include + +#include "../comm.h" + +static BOOL test_SerCxSys(HANDLE hComm) +{ + DCB dcb; + UCHAR XonChar, XoffChar; + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError()); + return FALSE; + } + + if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0')) + { + fprintf(stderr, "test_SerCxSys failure, expected XonChar and XoffChar to be set\n"); + return FALSE; + } + + /* swap XonChar/XoffChar */ + + XonChar = dcb.XonChar; + XoffChar = dcb.XoffChar; + dcb.XonChar = XoffChar; + dcb.XoffChar = XonChar; + if (!SetCommState(hComm, &dcb)) + { + fprintf(stderr, "SetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError()); + return FALSE; + } + + if ((dcb.XonChar != XoffChar) || (dcb.XoffChar != XonChar)) + { + 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)) + { + 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) + { + 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; + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); + return FALSE; + } + + if ((dcb.XonChar != '\0') || (dcb.XoffChar != '\0') || (dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0')) + { + fprintf(stderr, "test_SerCx2Sys failure, expected all characters to '\0'\n"); + return FALSE; + } + + return TRUE; +} + +int TestSerialChars(int argc, char* argv[]) +{ + BOOL result; + HANDLE hComm; + + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + if (!test_SerCxSys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + if (!test_SerCx2Sys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c index 48854ae49..ab2b190d2 100644 --- a/winpr/libwinpr/comm/test/TestSetCommState.c +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -24,13 +24,20 @@ #include "../comm.h" +static void init_empty_dcb(DCB *pDcb) +{ + ZeroMemory(pDcb, sizeof(DCB)); + pDcb->DCBlength = sizeof(DCB); + pDcb->XonChar = 1; + pDcb->XoffChar = 2; +} + static BOOL test_fParity(HANDLE hComm) { DCB dcb; BOOL result; - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -47,8 +54,7 @@ static BOOL test_fParity(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -71,8 +77,7 @@ static BOOL test_fParity(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -95,8 +100,7 @@ static BOOL test_fParity(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -119,8 +123,7 @@ static BOOL test_SerialSys(HANDLE hComm) DCB dcb; BOOL result; - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -137,8 +140,7 @@ static BOOL test_SerialSys(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -161,8 +163,7 @@ static BOOL test_SerialSys(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -192,8 +193,7 @@ static BOOL test_SerCxSys(HANDLE hComm) DCB dcb; BOOL result; - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -210,8 +210,7 @@ static BOOL test_SerCxSys(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -234,8 +233,7 @@ static BOOL test_SerCxSys(HANDLE hComm) return FALSE; } - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -272,8 +270,7 @@ static BOOL test_generic(HANDLE hComm) DCB dcb, dcb2; BOOL result; - ZeroMemory(&dcb, sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) { @@ -382,5 +379,11 @@ int TestSetCommState(int argc, char* argv[]) return EXIT_FAILURE; } + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } From feb44059412eae9f60defd1a648ceb18b13ad617 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 29 Apr 2014 22:25:07 +0200 Subject: [PATCH 14/61] wimpr-comm: got IOCTL_SERIAL_SET_LINE_CONTROL and IOCTL_SERIAL_GET_LINE_CONTROL --- winpr/libwinpr/comm/comm.c | 24 ++- winpr/libwinpr/comm/comm_ioctl.c | 37 ++++ winpr/libwinpr/comm/comm_ioctl.h | 25 ++- winpr/libwinpr/comm/comm_sercx2_sys.c | 7 +- winpr/libwinpr/comm/comm_sercx_sys.c | 32 ++-- winpr/libwinpr/comm/comm_serial_sys.c | 174 +++++++++++++++++- winpr/libwinpr/comm/test/CMakeLists.txt | 1 + .../libwinpr/comm/test/TestControlSettings.c | 121 ++++++++++++ 8 files changed, 393 insertions(+), 28 deletions(-) create mode 100644 winpr/libwinpr/comm/test/TestControlSettings.c diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index e09789342..86df72c86 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -223,7 +223,19 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) /* TMP: TODO: */ /* (...) */ - + SERIAL_LINE_CONTROL lineControl; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl, sizeof(SERIAL_LINE_CONTROL), &bytesReturned, NULL)) + { + DEBUG_WARN("GetCommState failure: could not get the control settings."); + goto error_handle; + } + + lpLocalDcb->ByteSize = lineControl.WordLength; + + lpLocalDcb->Parity = lineControl.Parity; + + lpLocalDcb->StopBits = lineControl.StopBits; + SERIAL_CHARS serialChars; if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) @@ -316,6 +328,16 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) return FALSE; } + SERIAL_LINE_CONTROL lineControl; + lineControl.StopBits = lpDCB->StopBits; + lineControl.Parity = lpDCB->Parity; + lineControl.WordLength = lpDCB->ByteSize; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_LINE_CONTROL, &lineControl, sizeof(SERIAL_LINE_CONTROL), NULL, 0, &bytesReturned, NULL)) + { + DEBUG_WARN("SetCommState failure: could not set the control settings."); + return FALSE; + } + /** upcomingTermios stage **/ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 9524ee73c..5f8d32ff2 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -212,6 +212,43 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe return TRUE; } } + case IOCTL_SERIAL_SET_LINE_CONTROL: + { + if (pRemoteSerialDriver->set_line_control) + { + SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL)); + if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + return pRemoteSerialDriver->set_line_control(pComm, pLineControl); + } + } + case IOCTL_SERIAL_GET_LINE_CONTROL: + { + if (pRemoteSerialDriver->get_line_control) + { + SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL)); + if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_line_control(pComm, pLineControl)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_LINE_CONTROL); + return TRUE; + } + } + } DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 593dd5b5f..d94c01582 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -43,9 +43,8 @@ extern "C" { #define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 #define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 - -/* #define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C */ -/* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */ +#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C +#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 /* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */ /* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */ @@ -97,6 +96,16 @@ extern "C" { /* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ +#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 _SERIAL_BAUD_RATE { @@ -115,6 +124,14 @@ typedef struct _SERIAL_CHARS } SERIAL_CHARS, *PSERIAL_CHARS; +typedef struct _SERIAL_LINE_CONTROL +{ + UCHAR StopBits; + UCHAR Parity; + UCHAR WordLength; +} SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL; + + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -129,6 +146,8 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 99bf8fe78..2baa1f2f7 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -61,12 +61,14 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_properties = NULL, .set_serial_chars = _set_serial_chars, .get_serial_chars = _get_serial_chars, + .set_line_control = NULL, + .get_line_control = NULL, }; REMOTE_SERIAL_DRIVER* SerCx2Sys_s() { - /* _SerCx2Sys completed with SerialSys or SerCxSys default functions */ + /* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */ //REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); @@ -74,6 +76,9 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate; _SerCx2Sys.get_properties = pSerCxSys->get_properties; + _SerCx2Sys.set_line_control = pSerCxSys->set_line_control; + _SerCx2Sys.get_line_control = pSerCxSys->get_line_control; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index bd4523bd4..d92093b5f 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -139,22 +139,16 @@ static const speed_t _SERCX_SYS_BAUD_TABLE[][3] = { static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) { int i; + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); - // TMP: TODO: + if (!pSerialSys->get_properties(pComm, pProperties)) + { + return FALSE; + } - // TMP: required? - // ZeroMemory(pProperties, sizeof(COMMPROP); + /* override some of the inherited properties from SerialSys ... */ - /* pProperties->PacketLength; */ - /* pProperties->PacketVersion; */ - /* pProperties->ServiceMask; */ - /* pProperties->Reserved1; */ - /* pProperties->MaxTxQueue; */ - /* pProperties->MaxRxQueue; */ pProperties->dwMaxBaud = BAUD_USER; - /* pProperties->ProvSubType; */ - /* pProperties->ProvCapabilities; */ - /* pProperties->SettableParams; */ pProperties->dwSettableBaud = 0; for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++) @@ -162,14 +156,6 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->dwSettableBaud |= _SERCX_SYS_BAUD_TABLE[i][2]; } - /* pProperties->SettableData; */ - /* pProperties->SettableStopParity; */ - /* pProperties->CurrentTxQueue; */ - /* pProperties->CurrentRxQueue; */ - /* pProperties->ProvSpec1; */ - /* pProperties->ProvSpec2; */ - /* pProperties->ProvChar[1]; */ - return TRUE; } @@ -256,17 +242,21 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_properties = _get_properties, .set_serial_chars = NULL, .get_serial_chars = NULL, + .set_line_control = NULL, + .get_line_control = NULL, }; REMOTE_SERIAL_DRIVER* SerCxSys_s() { - /* _SerCxSys completed with default SerialSys_s functions */ + /* _SerCxSys completed with inherited functions from SerialSys */ REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); _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; return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 315bf7e8f..e325395b2 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -142,6 +142,10 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) { int i; + /* FIXME: properties should be better probe. The current + * implementation just relies on the Linux' implementation. + */ + // TMP: TODO: // TMP: required? @@ -164,8 +168,10 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->dwSettableBaud |= _SERIAL_SYS_BAUD_TABLE[i][1]; } - /* pProperties->SettableData; */ - /* pProperties->SettableStopParity; */ + pProperties->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 /*| DATABITS_16 | DATABITS_16X*/; + + pProperties->wSettableStopParity = STOPBITS_10 | /*STOPBITS_15 |*/ STOPBITS_20 | PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_MARK | PARITY_SPACE; + /* pProperties->CurrentTxQueue; */ /* pProperties->CurrentRxQueue; */ /* pProperties->ProvSpec1; */ @@ -380,6 +386,168 @@ static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars) } +static BOOL _set_line_control(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLineControl) +{ + BOOL result = TRUE; + struct termios upcomingTermios; + + + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx + * + * The use of 5 data bits with 2 stop bits is an invalid + * combination, as is 6, 7, or 8 data bits with 1.5 stop bits. + * + * FIXME: prefered to let the underlying driver to deal with + * this issue. At least produce a warning message? + */ + + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* FIXME: use of a COMMPROP to validate new settings? */ + + switch (pLineControl->StopBits) + { + case STOP_BIT_1: + upcomingTermios.c_cflag &= ~CSTOPB; + break; + + case STOP_BITS_1_5: + DEBUG_WARN("Unsupported one and a half stop bits."); + break; + + case STOP_BITS_2: + upcomingTermios.c_cflag |= CSTOPB; + break; + + default: + DEBUG_WARN("unexpected number of stop bits: %d\n", pLineControl->StopBits); + result = FALSE; /* but keep on */ + break; + } + + + switch (pLineControl->Parity) + { + case NO_PARITY: + upcomingTermios.c_cflag &= ~(PARENB | PARODD | CMSPAR); + break; + + case ODD_PARITY: + upcomingTermios.c_cflag &= ~CMSPAR; + upcomingTermios.c_cflag |= PARENB | PARODD; + break; + + case EVEN_PARITY: + upcomingTermios.c_cflag &= ~(PARODD | CMSPAR); + upcomingTermios.c_cflag |= PARENB; + break; + + case MARK_PARITY: + upcomingTermios.c_cflag |= PARENB | PARODD | CMSPAR; + break; + + case SPACE_PARITY: + upcomingTermios.c_cflag &= ~PARODD; + upcomingTermios.c_cflag |= PARENB | CMSPAR; + break; + + default: + DEBUG_WARN("unexpected type of parity: %d\n", pLineControl->Parity); + result = FALSE; /* but keep on */ + break; + } + + switch (pLineControl->WordLength) + { + case 5: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS5; + break; + + case 6: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS6; + break; + + case 7: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS7; + break; + + case 8: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS8; + break; + + default: + DEBUG_WARN("unexpected number od data bits per character: %d\n", pLineControl->WordLength); + result = FALSE; /* but keep on */ + break; + } + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + return FALSE; + } + + return result; +} + + +static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineControl) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + pLineControl->StopBits = (currentTermios.c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BIT_1; + + if (!(currentTermios.c_cflag & PARENB)) + { + pLineControl->Parity = NO_PARITY; + } + else if (currentTermios.c_cflag & CMSPAR) + { + pLineControl->Parity = (currentTermios.c_cflag & PARODD) ? MARK_PARITY : SPACE_PARITY; + } + else + { + /* PARENB is set */ + pLineControl->Parity = (currentTermios.c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY; + } + + switch (currentTermios.c_cflag & CSIZE) + { + case CS5: + pLineControl->WordLength = 5; + break; + case CS6: + pLineControl->WordLength = 6; + break; + case CS7: + pLineControl->WordLength = 7; + break; + default: + pLineControl->WordLength = 8; + break; + } + + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { @@ -390,6 +558,8 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_properties = _get_properties, .set_serial_chars = _set_serial_chars, .get_serial_chars = _get_serial_chars, + .set_line_control = _set_line_control, + .get_line_control = _get_line_control }; diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt index cad34b38d..c2b549ca3 100644 --- a/winpr/libwinpr/comm/test/CMakeLists.txt +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -10,6 +10,7 @@ set(${MODULE_PREFIX}_TESTS TestGetCommState.c TestSetCommState.c TestSerialChars.c + TestControlSettings.c TestCommMonitor.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/comm/test/TestControlSettings.c b/winpr/libwinpr/comm/test/TestControlSettings.c new file mode 100644 index 000000000..15963da30 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestControlSettings.c @@ -0,0 +1,121 @@ +/** + * 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 + +#include +#include + +#include "../comm.h" + +int TestControlSettings(int argc, char* argv[]) +{ + BOOL result; + HANDLE hComm; + DCB dcb; + + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); + return FALSE; + } + + /* Test 1 */ + + dcb.ByteSize = 5; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = MARKPARITY; + + if (!SetCommState(hComm, &dcb)) + { + fprintf(stderr, "SetCommState failure; GetLastError(): %0.8x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); + return FALSE; + } + + if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY)) + { + fprintf(stderr, "test1 failed.\n"); + return FALSE; + } + + + /* Test 2 */ + + dcb.ByteSize = 8; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = NOPARITY; + + if (!SetCommState(hComm, &dcb)) + { + fprintf(stderr, "SetCommState failure; GetLastError(): %0.8x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); + return FALSE; + } + + if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY)) + { + fprintf(stderr, "test2 failed.\n"); + return FALSE; + } + + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} From 494b7e8f9306e706d23be7e5e574c5fdbcb7db6f Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Thu, 1 May 2014 00:04:55 +0200 Subject: [PATCH 15/61] winpr-comm: fixed DCB's fBinary and fParity flags --- winpr/libwinpr/comm/comm.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 86df72c86..acc8f15f5 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -216,9 +216,13 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) } lpLocalDcb->BaudRate = baudRate.BaudRate; - lpLocalDcb->fBinary = TRUE; /* TMP: TODO: seems equivalent to the raw mode */ + lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0; + if (!lpLocalDcb->fBinary) + { + DEBUG_WARN("Unexpected nonbinary mode, consider to unset the ICANON flag."); + } - lpLocalDcb->fParity = (currentState.c_cflag & PARENB) != 0; + lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; /* TMP: TODO: */ /* (...) */ @@ -349,21 +353,24 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) return FALSE; } - if (!lpDCB->fBinary) + if (lpDCB->fBinary) { - DEBUG_WARN("unexpected nonbinary mode transfers"); - SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; - } - // TMP: set the raw mode here? - - if (lpDCB->fParity) - { - upcomingTermios.c_cflag |= PARENB; + upcomingTermios.c_lflag &= ~ICANON; + // TMP: complete the raw mode here? } else { - upcomingTermios.c_cflag &= ~PARENB; + upcomingTermios.c_lflag |= ICANON; + DEBUG_WARN("Unexpected nonbinary mode, consider to unset the ICANON flag."); + } + + if (lpDCB->fParity) + { + upcomingTermios.c_iflag |= INPCK; + } + else + { + upcomingTermios.c_iflag &= ~INPCK; } // TMP: TODO: From c2b024512a21f9e64c3d318a5b96d2e764dd797b Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 6 May 2014 16:08:58 +0200 Subject: [PATCH 16/61] winpr-comm: got IOCTL_SERIAL_SET_HANDFLOW / IOCTL_SERIAL_GET_HANDFLOW --- channels/serial/client/serial_main.c | 6 +- winpr/libwinpr/comm/comm.c | 174 ++++++++- winpr/libwinpr/comm/comm_ioctl.c | 47 ++- winpr/libwinpr/comm/comm_ioctl.h | 38 +- winpr/libwinpr/comm/comm_sercx2_sys.c | 11 +- winpr/libwinpr/comm/comm_sercx_sys.c | 263 ++++++++++++++ winpr/libwinpr/comm/comm_serial_sys.c | 381 +++++++++++++++++--- winpr/libwinpr/comm/test/CMakeLists.txt | 1 + winpr/libwinpr/comm/test/TestCommConfig.c | 11 +- winpr/libwinpr/comm/test/TestHandflow.c | 86 +++++ winpr/libwinpr/comm/test/TestSerialChars.c | 23 +- winpr/libwinpr/comm/test/TestSetCommState.c | 1 + 12 files changed, 970 insertions(+), 72 deletions(-) create mode 100644 winpr/libwinpr/comm/test/TestHandflow.c diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 5285aa854..c592f607d 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -298,7 +298,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) break; case ERROR_NOT_SUPPORTED: - irp->IoStatus = STATUS_INVALID_PARAMETER; + irp->IoStatus = STATUS_NOT_SUPPORTED; break; case ERROR_INSUFFICIENT_BUFFER: @@ -309,6 +309,10 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_INVALID_PARAMETER; break; + case ERROR_CALL_NOT_IMPLEMENTED: + irp->IoStatus = STATUS_NOT_IMPLEMENTED; + break; + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index acc8f15f5..b639c840f 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -224,8 +224,67 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; - /* TMP: TODO: */ - /* (...) */ + SERIAL_HANDFLOW handflow; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow, sizeof(SERIAL_HANDFLOW), &bytesReturned, NULL)) + { + DEBUG_WARN("GetCommState failure: could not get the handflow settings."); + goto error_handle; + } + + lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0; + + lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0; + + if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE; + } + else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL) + { + lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE; + } + else + { + lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE; + } + + lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0; + + lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0; + + lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0; + + lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0; + + lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0; + + lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0; + + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE; + } + else if (handflow.FlowReplace & SERIAL_RTS_CONTROL) + { + lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE; + } + else + { + lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE; + } + + // FIXME: how to get the RTS_CONTROL_TOGGLE state? Does it match the UART 16750's Autoflow Control Enabled bit in its Modem Control Register (MCR) + + + lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0; + + /* lpLocalDcb->fDummy2 not used */ + + lpLocalDcb->wReserved = 0; /* must be zero */ + + lpLocalDcb->XonLim = handflow.XonLimit; + + lpLocalDcb->XoffLim = handflow.XoffLimit; SERIAL_LINE_CONTROL lineControl; if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl, sizeof(SERIAL_LINE_CONTROL), &bytesReturned, NULL)) @@ -316,7 +375,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) } SERIAL_CHARS serialChars; - if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) /* as of today, required for BreakChar */ { DEBUG_WARN("SetCommState failure: could not get the initial serial chars."); return FALSE; @@ -325,7 +384,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) serialChars.XoffChar = lpDCB->XoffChar; serialChars.ErrorChar = lpDCB->ErrorChar; serialChars.EofChar = lpDCB->EofChar; - serialChars.EventChar = lpDCB->EvtChar; + serialChars.EventChar = lpDCB->EvtChar; if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars, sizeof(SERIAL_CHARS), NULL, 0, &bytesReturned, NULL)) { DEBUG_WARN("SetCommState failure: could not set the serial chars."); @@ -343,6 +402,113 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) } + SERIAL_HANDFLOW handflow; + ZeroMemory(&handflow, sizeof(SERIAL_HANDFLOW)); + + if (lpDCB->fOutxCtsFlow) + { + handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE; + } + + + if (lpDCB->fOutxDsrFlow) + { + handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE; + } + + switch (lpDCB->fDtrControl) + { + case SERIAL_DTR_HANDSHAKE: + handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE; + break; + + case SERIAL_DTR_CONTROL: + handflow.ControlHandShake |= DTR_CONTROL_ENABLE; + break; + + case DTR_CONTROL_DISABLE: + /* do nothing since handflow is init-zeroed */ + break; + + default: + DEBUG_WARN("Unexpected fDtrControl value: %d\n", lpDCB->fDtrControl); + return FALSE; + } + + if (lpDCB->fDsrSensitivity) + { + handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY; + } + + if (lpDCB->fTXContinueOnXoff) + { + handflow.FlowReplace |= SERIAL_XOFF_CONTINUE; + } + + if (lpDCB->fOutX) + { + handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT; + } + + if (lpDCB->fInX) + { + handflow.FlowReplace |= SERIAL_AUTO_RECEIVE; + } + + if (lpDCB->fErrorChar) + { + handflow.FlowReplace |= SERIAL_ERROR_CHAR; + } + + if (lpDCB->fNull) + { + handflow.FlowReplace |= SERIAL_NULL_STRIPPING; + } + + switch (lpDCB->fRtsControl) + { + case RTS_CONTROL_TOGGLE: + DEBUG_WARN("Unsupported RTS_CONTROL_TOGGLE feature"); + // FIXME: see also GetCommState() + return FALSE; + + case RTS_CONTROL_HANDSHAKE: + handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE; + break; + + case RTS_CONTROL_ENABLE: + handflow.FlowReplace |= SERIAL_RTS_CONTROL; + break; + + case RTS_CONTROL_DISABLE: + /* do nothing since handflow is init-zeroed */ + break; + + default: + DEBUG_WARN("Unexpected fRtsControl value: %d\n", lpDCB->fRtsControl); + return FALSE; + } + + if (lpDCB->fAbortOnError) + { + handflow.ControlHandShake |= SERIAL_ERROR_ABORT; + } + + /* lpDCB->fDummy2 not used */ + + /* lpLocalDcb->wReserved ignored */ + + handflow.XonLimit = lpDCB->XonLim; + + handflow.XoffLimit = lpDCB->XoffLim; + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow, sizeof(SERIAL_HANDFLOW), NULL, 0, &bytesReturned, NULL)) + { + DEBUG_WARN("SetCommState failure: could not set the handflow settings."); + return FALSE; + } + + /** upcomingTermios stage **/ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 5f8d32ff2..0b8273a20 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -135,6 +135,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe return pRemoteSerialDriver->set_baud_rate(pComm, pBaudRate); } + break; } case IOCTL_SERIAL_GET_BAUD_RATE: { @@ -155,6 +156,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe *lpBytesReturned = sizeof(SERIAL_BAUD_RATE); return TRUE; } + break; } case IOCTL_SERIAL_GET_PROPERTIES: { @@ -175,6 +177,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe *lpBytesReturned = sizeof(COMMPROP); return TRUE; } + break; } case IOCTL_SERIAL_SET_CHARS: { @@ -191,6 +194,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe return pRemoteSerialDriver->set_serial_chars(pComm, pSerialChars); } + break; } case IOCTL_SERIAL_GET_CHARS: { @@ -211,6 +215,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe *lpBytesReturned = sizeof(SERIAL_CHARS); return TRUE; } + break; } case IOCTL_SERIAL_SET_LINE_CONTROL: { @@ -227,6 +232,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe return pRemoteSerialDriver->set_line_control(pComm, pLineControl); } + break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { @@ -247,11 +253,50 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe *lpBytesReturned = sizeof(SERIAL_LINE_CONTROL); return TRUE; } + break; + } + case IOCTL_SERIAL_SET_HANDFLOW: + { + if (pRemoteSerialDriver->set_handflow) + { + SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_HANDFLOW)); + if (nInBufferSize < sizeof(SERIAL_HANDFLOW)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + return pRemoteSerialDriver->set_handflow(pComm, pHandflow); + } + break; + } + case IOCTL_SERIAL_GET_HANDFLOW: + { + if (pRemoteSerialDriver->get_handflow) + { + SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_HANDFLOW)); + if (nOutBufferSize < sizeof(SERIAL_HANDFLOW)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_handflow(pComm, pHandflow)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_HANDFLOW); + return TRUE; + } + break; } } - DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); + DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); return FALSE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index d94c01582..b636920e1 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -67,8 +67,8 @@ extern "C" { /* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */ /* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ /* IOCTL_SERIAL_PURGE 0x001B004C */ -/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */ -/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */ +#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 +#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 /* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */ /* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ /* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ @@ -132,6 +132,38 @@ typedef struct _SERIAL_LINE_CONTROL } SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL; +typedef struct _SERIAL_HANDFLOW +{ + ULONG ControlHandShake; + ULONG FlowReplace; + LONG XonLimit; + LONG 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) + + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -148,6 +180,8 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 2baa1f2f7..9e4352cd3 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -63,22 +63,31 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_serial_chars = _get_serial_chars, .set_line_control = NULL, .get_line_control = NULL, + .set_handflow = NULL, + .get_handflow = NULL, }; REMOTE_SERIAL_DRIVER* SerCx2Sys_s() { /* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */ - //REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); _SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate; _SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate; + _SerCx2Sys.get_properties = pSerCxSys->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; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index d92093b5f..8dad85738 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -231,6 +231,267 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) return FALSE; } +/* hard-coded in N_TTY */ +#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ +#define TTY_THRESHOLD_UNTHROTTLE 128 + +/* FIXME: mostly copied/pasted from comm_serial_sys.c, better share this code */ +static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) +{ + BOOL result = TRUE; + struct termios upcomingTermios; + + /* logical XOR */ + if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || + ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) + { + DEBUG_WARN("SERIAL_DTR_CONTROL cannot be different SERIAL_RTS_CONTROL, HUPCL will be set according SERIAL_RTS_CONTROL."); + result = FALSE; /* but keep on */ + } + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* ControlHandShake */ + + if (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) + { + upcomingTermios.c_cflag |= HUPCL; + } + else + { + upcomingTermios.c_cflag &= ~HUPCL; + + /* FIXME: is the DTR line also needs to be forced to a disable state? */ + } + + if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + /* DTR/DSR flow control not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + if (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) + { + upcomingTermios.c_cflag |= CRTSCTS; + } + else + { + upcomingTermios.c_cflag &= ~CRTSCTS; + } + + if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE) + { + /* DTR/DSR flow control not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* SERIAL_DCD_HANDSHAKE unsupported by SerCx */ + if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) + { + DEBUG_WARN("Attempt to set SERIAL_DCD_HANDSHAKE (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + /* SERIAL_DSR_SENSITIVITY unsupported by SerCx */ + if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) + { + DEBUG_WARN("Attempt to set SERIAL_DSR_SENSITIVITY (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + /* SERIAL_ERROR_ABORT unsupported by SerCx */ + if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) + { + DEBUG_WARN("Attempt to set SERIAL_ERROR_ABORT (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + + /* FlowReplace */ + + /* SERIAL_AUTO_TRANSMIT unsupported by SerCx */ + if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT) + { + DEBUG_WARN("Attempt to set SERIAL_AUTO_TRANSMIT (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + + /* SERIAL_AUTO_RECEIVE unsupported by SerCx */ + if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE) + { + DEBUG_WARN("Attempt to set SERIAL_AUTO_RECEIVE (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + /* SERIAL_ERROR_CHAR unsupported by SerCx */ + if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR) + { + DEBUG_WARN("Attempt to set SERIAL_ERROR_CHAR (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + /* SERIAL_NULL_STRIPPING unsupported by SerCx */ + if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING) + { + DEBUG_WARN("Attempt to set SERIAL_NULL_STRIPPING (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + /* SERIAL_BREAK_CHAR unsupported by SerCx */ + if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR) + { + DEBUG_WARN("Attempt to set SERIAL_BREAK_CHAR (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + if (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) + { + upcomingTermios.c_cflag |= HUPCL; + } + else + { + upcomingTermios.c_cflag &= ~HUPCL; + + /* FIXME: is the RTS line also needs to be forced to a disable state? */ + } + + if (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) + { + upcomingTermios.c_cflag |= CRTSCTS; + } + else + { + upcomingTermios.c_cflag &= ~CRTSCTS; + } + + /* SERIAL_XOFF_CONTINUE unsupported by SerCx */ + if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE) + { + DEBUG_WARN("Attempt to set SERIAL_XOFF_CONTINUE (not implemented)"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; /* but keep on */ + } + + + /* XonLimit */ + + // FIXME: could be implemented during read/write I/O + if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE) + { + DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %d", pHandflow->XonLimit); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* XoffChar */ + + // FIXME: could be implemented during read/write I/O + if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE) + { + DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %d", pHandflow->XoffLimit); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + return FALSE; + } + + return result; +} + + +/* FIXME: mostly copied/pasted from comm_serial_sys.c, better share this code */ +static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + + /* ControlHandShake */ + + pHandflow->ControlHandShake = 0; + + if (currentTermios.c_cflag & HUPCL) + pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL; + + /* SERIAL_DTR_HANDSHAKE unsupported */ + + if (currentTermios.c_cflag & CRTSCTS) + pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE; + + /* SERIAL_DSR_HANDSHAKE unsupported */ + + /* SERIAL_DCD_HANDSHAKE unsupported by SerCx */ + + /* SERIAL_DSR_SENSITIVITY unsupported by SerCx */ + + /* SERIAL_ERROR_ABORT unsupported by SerCx */ + + + /* FlowReplace */ + + pHandflow->FlowReplace = 0; + + /* SERIAL_AUTO_TRANSMIT unsupported by SerCx */ + + /* SERIAL_AUTO_RECEIVE unsupported by SerCx */ + + /* SERIAL_ERROR_CHAR unsupported by SerCx */ + + /* SERIAL_NULL_STRIPPING unsupported by SerCx */ + + /* SERIAL_BREAK_CHAR unsupported by SerCx */ + + if (currentTermios.c_cflag & HUPCL) + pHandflow->FlowReplace |= SERIAL_RTS_CONTROL; + + if (currentTermios.c_cflag & CRTSCTS) + pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE; + + /* SERIAL_XOFF_CONTINUE unsupported by SerCx */ + + + /* XonLimit */ + + pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE; + + + /* XoffLimit */ + + pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE; + + return TRUE; +} + + /* specific functions only */ static REMOTE_SERIAL_DRIVER _SerCxSys = @@ -244,6 +505,8 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_serial_chars = NULL, .set_line_control = NULL, .get_line_control = NULL, + .set_handflow = _set_handflow, + .get_handflow = _get_handflow, }; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index e325395b2..bd58c7ab3 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -148,6 +148,8 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) // TMP: TODO: + // TMP: COMMPROP_INITIALIZED ? + // TMP: required? // ZeroMemory(pProperties, sizeof(COMMPROP); @@ -158,9 +160,17 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) /* pProperties->MaxTxQueue; */ /* pProperties->MaxRxQueue; */ pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */ - /* pProperties->ProvSubType; */ - /* pProperties->ProvCapabilities; */ - /* pProperties->SettableParams; */ + + /* FIXME: what about PST_RS232? */ + pProperties->dwProvSubType = PST_UNSPECIFIED; + + /* TMP: TODO: to be finalized */ + pProperties->dwProvCapabilities = + /*PCF_16BITMODE | PCF_DTRDSR | PCF_INTTIMEOUTS |*/ PCF_PARITY_CHECK | /*PCF_RLSD | */ + PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS | PCF_TOTALTIMEOUTS |*/ PCF_XONXOFF; + + /* TMP: TODO: double check SP_RLSD */ + pProperties->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY | SP_PARITY_CHECK | /*SP_RLSD |*/ SP_STOPBITS; pProperties->dwSettableBaud = 0; for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++) @@ -251,15 +261,17 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) } /** - * NOTE: Only XonChar and XoffChar are plenty supported with Linux - * N_TTY line discipline. + * NOTE: Only XonChar and XoffChar are plenty supported with the Linux + * N_TTY line discipline. * * ERRORS: * ERROR_IO_DEVICE * ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same; + * ERROR_NOT_SUPPORTED */ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChars) { + BOOL result = TRUE; struct termios upcomingTermios; ZeroMemory(&upcomingTermios, sizeof(struct termios)); @@ -282,55 +294,46 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar * special character meaning is replaced by the timeout * meaning. * - * It doesn't seem the case of the Linux's implementation but - * in our context, the cannonical mode (fBinary=FALSE) should - * never be enabled. + * EofChar and c_cc[VEOF] are not quite the same, prefer to + * don't use c_cc[VEOF] at all. + * + * FIXME: might be implemented during read/write I/O */ - - if (upcomingTermios.c_lflag & ICANON) + if (pSerialChars->EofChar != '\0') { - upcomingTermios.c_cc[VEOF] = pSerialChars->EofChar; - DEBUG_WARN("c_cc[VEOF] is not supposed to be modified!"); + DEBUG_WARN("EofChar='%c' cannot be set\n", pSerialChars->EofChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ } - /* else let c_cc[VEOF] unchanged */ - /* According the Linux's n_tty discipline, charaters with a * parity error can only be let unchanged, replaced by \0 or * get the prefix the prefix \377 \0 */ - if (pSerialChars->ErrorChar == '\0') + /* FIXME: see also: _set_handflow() */ + if (pSerialChars->ErrorChar != '\0') { - /* Also suppose PARENB !IGNPAR !PARMRK to be effective */ - upcomingTermios.c_iflag |= INPCK; - } - else - { - /* FIXME: develop a line discipline dedicated to the - * RDP redirection. Erroneous characters might also be - * caught during read/write operations? - */ - DEBUG_WARN("ErrorChar='%c' cannot be set, characters with a parity error will be let unchanged.\n", pSerialChars->ErrorChar); + DEBUG_WARN("ErrorChar='%c' (0x%x) cannot be set (unsupported).\n", pSerialChars->ErrorChar, pSerialChars->ErrorChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ } - if (pSerialChars->BreakChar == '\0') + /* FIXME: see also: _set_handflow() */ + if (pSerialChars->BreakChar != '\0') { - upcomingTermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK); - } - else - { - /* FIXME: develop a line discipline dedicated to the - * RDP redirection. Break characters might also be - * caught during read/write operations? - */ - DEBUG_WARN("BreakChar='%c' cannot be set.\n", pSerialChars->ErrorChar); + DEBUG_WARN("BreakChar='%c' (0x%x) cannot be set (unsupported).\n", pSerialChars->BreakChar, pSerialChars->BreakChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ } - /* FIXME: Didn't find anything similar inside N_TTY. Develop a - * line discipline dedicated to the RDP redirection. - */ - DEBUG_WARN("EventChar='%c' cannot be set\n", pSerialChars->EventChar); + /* TMP: FIXME: Didn't find anything similar yet on Linux */ + if (pSerialChars->EventChar != '\0') + { + DEBUG_WARN("EventChar='%c' (0x%x) cannot be set\n", pSerialChars->EventChar, pSerialChars->EventChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } upcomingTermios.c_cc[VSTART] = pSerialChars->XonChar; @@ -343,7 +346,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar return FALSE; } - return TRUE; + return result; } @@ -360,23 +363,14 @@ static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars) ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS)); - if (currentTermios.c_lflag & ICANON) - { - pSerialChars->EofChar = currentTermios.c_cc[VEOF]; - } + /* EofChar unsupported */ - /* FIXME: see also: _set_serial_chars() */ - if (currentTermios.c_iflag & INPCK) - pSerialChars->ErrorChar = '\0'; - /* else '\0' is currently used anyway */ + /* ErrorChar unsupported */ + + /* BreakChar unsupported */ - /* FIXME: see also: _set_serial_chars() */ - if (currentTermios.c_iflag & ~IGNBRK & BRKINT) - pSerialChars->BreakChar = '\0'; - /* else '\0' is currently used anyway */ - - /* FIXME: see also: _set_serial_chars() */ - pSerialChars->EventChar = '\0'; + /* TMP: FIXME: see also: _set_serial_chars() */ + /* EventChar */ pSerialChars->XonChar = currentTermios.c_cc[VSTART]; @@ -548,6 +542,279 @@ static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineContr } +/* hard-coded in N_TTY */ +#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ +#define TTY_THRESHOLD_UNTHROTTLE 128 + +static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) +{ + BOOL result = TRUE; + struct termios upcomingTermios; + + /* logical XOR */ + if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || + ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) + { + DEBUG_WARN("SERIAL_DTR_CONTROL cannot be different SERIAL_RTS_CONTROL, HUPCL will be set according SERIAL_RTS_CONTROL."); + result = FALSE; /* but keep on */ + } + + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* ControlHandShake */ + + if (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) + { + upcomingTermios.c_cflag |= HUPCL; + } + else + { + upcomingTermios.c_cflag &= ~HUPCL; + + /* FIXME: is the DTR line also needs to be forced to a disable state? */ + } + + if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + /* DTR/DSR flow control not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + + if (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) + { + upcomingTermios.c_cflag |= CRTSCTS; + } + else + { + upcomingTermios.c_cflag &= ~CRTSCTS; + } + + if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE) + { + /* DTR/DSR flow control not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) + { + /* DCD flow control not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_DCD_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + // TMP: FIXME: could be implemented during read/write I/O + if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) + { + /* DSR line control not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_SENSITIVITY feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + // TMP: FIXME: could be implemented during read/write I/O + if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) + { + /* Aborting operations on error not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_ERROR_ABORT feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* FlowReplace */ + + if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT) + { + upcomingTermios.c_iflag |= IXON; + } + else + { + upcomingTermios.c_iflag &= ~IXON; + } + + if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE) + { + upcomingTermios.c_iflag |= IXOFF; + } + else + { + upcomingTermios.c_iflag &= ~IXOFF; + } + + // TMP: FIXME: could be implemented during read/write I/O + if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR) + { + DEBUG_WARN("Attempt to use the unsupported SERIAL_ERROR_CHAR feature. A character with a parity error or framing error will be read as \0"); + + /* errors will be replaced by the character '\0' */ + upcomingTermios.c_iflag &= ~IGNPAR; + } + else + { + upcomingTermios.c_iflag |= IGNPAR; + } + + if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING) + { + upcomingTermios.c_iflag |= IGNBRK; + } + else + { + upcomingTermios.c_iflag &= ~IGNBRK; + } + + // TMP: FIXME: could be implemented during read/write I/O + if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR) + { + DEBUG_WARN("Attempt to use the unsupported SERIAL_BREAK_CHAR feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + if (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) + { + upcomingTermios.c_cflag |= HUPCL; + } + else + { + upcomingTermios.c_cflag &= ~HUPCL; + + /* FIXME: is the RTS line also needs to be forced to a disable state? */ + } + + if (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) + { + upcomingTermios.c_cflag |= CRTSCTS; + } + else + { + upcomingTermios.c_cflag &= ~CRTSCTS; + } + + + // FIXME: could be implemented during read/write I/O + if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE) + { + /* not supported on Linux */ + DEBUG_WARN("Attempt to use the unsupported SERIAL_XOFF_CONTINUE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* XonLimit */ + + // FIXME: could be implemented during read/write I/O + if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE) + { + DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %d", pHandflow->XonLimit); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* XoffChar */ + + // FIXME: could be implemented during read/write I/O + if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE) + { + DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %d", pHandflow->XoffLimit); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + return FALSE; + } + + return result; +} + + +static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + + /* ControlHandShake */ + + pHandflow->ControlHandShake = 0; + + if (currentTermios.c_cflag & HUPCL) + pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL; + + /* SERIAL_DTR_HANDSHAKE unsupported */ + + if (currentTermios.c_cflag & CRTSCTS) + pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE; + + /* SERIAL_DSR_HANDSHAKE unsupported */ + + /* SERIAL_DCD_HANDSHAKE unsupported */ + + /* SERIAL_DSR_SENSITIVITY unsupported */ + + /* SERIAL_ERROR_ABORT unsupported */ + + + /* FlowReplace */ + + pHandflow->FlowReplace = 0; + + if (currentTermios.c_iflag & IXON) + pHandflow->FlowReplace |= SERIAL_AUTO_TRANSMIT; + + if (currentTermios.c_iflag & IXOFF) + pHandflow->FlowReplace |= SERIAL_AUTO_RECEIVE; + + if (!(currentTermios.c_iflag & IGNPAR)) + pHandflow->FlowReplace |= SERIAL_ERROR_CHAR; + + if (currentTermios.c_iflag & IGNBRK) + pHandflow->FlowReplace |= SERIAL_NULL_STRIPPING; + + /* SERIAL_BREAK_CHAR unsupported */ + + if (currentTermios.c_cflag & HUPCL) + pHandflow->FlowReplace |= SERIAL_RTS_CONTROL; + + if (currentTermios.c_cflag & CRTSCTS) + pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE; + + /* SERIAL_XOFF_CONTINUE unsupported */ + + + /* XonLimit */ + + pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE; + + + /* XoffLimit */ + + pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE; + + return TRUE; +} + static REMOTE_SERIAL_DRIVER _SerialSys = { @@ -559,7 +826,9 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_serial_chars = _set_serial_chars, .get_serial_chars = _get_serial_chars, .set_line_control = _set_line_control, - .get_line_control = _get_line_control + .get_line_control = _get_line_control, + .set_handflow = _set_handflow, + .get_handflow = _get_handflow, }; diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt index c2b549ca3..d81c3228c 100644 --- a/winpr/libwinpr/comm/test/CMakeLists.txt +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -11,6 +11,7 @@ set(${MODULE_PREFIX}_TESTS TestSetCommState.c TestSerialChars.c TestControlSettings.c + TestHandflow.c TestCommMonitor.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c index f8953d21b..b5e212ab6 100644 --- a/winpr/libwinpr/comm/test/TestCommConfig.c +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -108,8 +108,6 @@ int TestCommConfig(int argc, char* argv[]) return EXIT_FAILURE; } - /* TODO: */ - dcb.BaudRate = CBR_57600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; @@ -120,7 +118,7 @@ int TestCommConfig(int argc, char* argv[]) if (!success) { fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); - return 0; + return EXIT_FAILURE; } success = GetCommState(hComm, &dcb); @@ -131,8 +129,11 @@ int TestCommConfig(int argc, char* argv[]) return 0; } - fprintf(stderr, "BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", - (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) || (dcb.StopBits != ONESTOPBIT)) + { + fprintf(stderr, "Got an unexpeted value among: BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + } CloseHandle(hComm); diff --git a/winpr/libwinpr/comm/test/TestHandflow.c b/winpr/libwinpr/comm/test/TestHandflow.c new file mode 100644 index 000000000..6f1286d00 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestHandflow.c @@ -0,0 +1,86 @@ +/** + * 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 +#include + +#include +#include + +#include "../comm.h" + +static BOOL test_SerialSys(HANDLE hComm) +{ + // TMP: TODO: + return TRUE; +} + + +int TestHandflow(int argc, char* argv[]) +{ + BOOL result; + HANDLE hComm; + + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + if (!test_SerialSys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + /* _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); */ + /* if (!test_SerCxSys(hComm)) */ + /* { */ + /* fprintf(stderr, "test_SerCxSys failure\n"); */ + /* return EXIT_FAILURE; */ + /* } */ + + /* _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); */ + /* if (!test_SerCx2Sys(hComm)) */ + /* { */ + /* fprintf(stderr, "test_SerCxSys failure\n"); */ + /* return EXIT_FAILURE; */ + /* } */ + + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestSerialChars.c b/winpr/libwinpr/comm/test/TestSerialChars.c index 4937b60e2..7ca879ea4 100644 --- a/winpr/libwinpr/comm/test/TestSerialChars.c +++ b/winpr/libwinpr/comm/test/TestSerialChars.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -29,6 +30,16 @@ static BOOL test_SerCxSys(HANDLE hComm) DCB dcb; UCHAR XonChar, XoffChar; + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(((WINPR_COMM*)hComm)->fd, ¤tTermios) < 0) + { + fprintf(stderr, "tcgetattr failure.\n"); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); if (!GetCommState(hComm, &dcb)) @@ -43,6 +54,14 @@ static BOOL test_SerCxSys(HANDLE hComm) return FALSE; } + + /* retrieve Xon/Xoff chars */ + if ((dcb.XonChar != currentTermios.c_cc[VSTART]) || (dcb.XoffChar != currentTermios.c_cc[VSTOP])) + { + fprintf(stderr, "test_SerCxSys failure, could not retrieve XonChar and XoffChar\n"); + return FALSE; + } + /* swap XonChar/XoffChar */ XonChar = dcb.XonChar; @@ -98,9 +117,9 @@ static BOOL test_SerCx2Sys(HANDLE hComm) return FALSE; } - if ((dcb.XonChar != '\0') || (dcb.XoffChar != '\0') || (dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0')) + if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') || (dcb.XonChar != '\0') || (dcb.XoffChar != '\0')) { - fprintf(stderr, "test_SerCx2Sys failure, expected all characters to '\0'\n"); + fprintf(stderr, "test_SerCx2Sys failure, expected all characters to be: '\\0'\n"); return FALSE; } diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c index ab2b190d2..0ddfb89fe 100644 --- a/winpr/libwinpr/comm/test/TestSetCommState.c +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -314,6 +314,7 @@ static BOOL test_generic(HANDLE hComm) return TRUE; } + int TestSetCommState(int argc, char* argv[]) { BOOL result; From ff4d7d569b5b72233cdd3dcadaaabc96542bc366 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 6 May 2014 16:45:05 +0200 Subject: [PATCH 17/61] winpr-comm: slightly improved GetCommProperties() --- winpr/libwinpr/comm/comm_ioctl.h | 15 +++++++++++++ winpr/libwinpr/comm/comm_sercx2_sys.c | 1 + winpr/libwinpr/comm/comm_serial_sys.c | 32 ++++++++++++++++++--------- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index b636920e1..5ef8ff407 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -163,6 +163,21 @@ typedef struct _SERIAL_HANDFLOW #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) /** * A function might be NULL if not supported by the underlying remote driver. diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 9e4352cd3..7f657f827 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -22,6 +22,7 @@ #ifndef _WIN32 +#include "comm_serial_sys.h" #include "comm_sercx_sys.h" #include "comm_sercx2_sys.h" diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index bd58c7ab3..aaf5fe64c 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -142,23 +142,33 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) { int i; + /* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680684%28v=vs.85%29.aspx + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363189%28v=vs.85%29.aspx + */ + /* FIXME: properties should be better probe. The current * implementation just relies on the Linux' implementation. */ // TMP: TODO: - // TMP: COMMPROP_INITIALIZED ? - // TMP: required? - // ZeroMemory(pProperties, sizeof(COMMPROP); + if (pProperties->dwProvSpec1 != COMMPROP_INITIALIZED) + { + ZeroMemory(pProperties, sizeof(COMMPROP)); + pProperties->wPacketLength = sizeof(COMMPROP); + } - /* pProperties->PacketLength; */ - /* pProperties->PacketVersion; */ - /* pProperties->ServiceMask; */ - /* pProperties->Reserved1; */ + pProperties->wPacketVersion = 2; + + pProperties->dwServiceMask = SERIAL_SP_SERIALCOMM; + + /* pProperties->Reserved1; not used */ + + // TMP: FIXME: related to the UART's FIFO ? /* pProperties->MaxTxQueue; */ /* pProperties->MaxRxQueue; */ + pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */ /* FIXME: what about PST_RS232? */ @@ -182,11 +192,13 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->wSettableStopParity = STOPBITS_10 | /*STOPBITS_15 |*/ STOPBITS_20 | PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_MARK | PARITY_SPACE; + // TMP: FIXME: related to the UART's FIFO ? /* pProperties->CurrentTxQueue; */ /* pProperties->CurrentRxQueue; */ - /* pProperties->ProvSpec1; */ - /* pProperties->ProvSpec2; */ - /* pProperties->ProvChar[1]; */ + + /* pProperties->ProvSpec1; see above */ + /* pProperties->ProvSpec2; ignored */ + /* pProperties->ProvChar[1]; ignored */ return TRUE; } From 4c743de69cca6c4a7f1b471ef399d714eae45853 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 12 May 2014 17:33:56 +0200 Subject: [PATCH 18/61] winpr-comm: got IOCTL_SERIAL_SET_TIMEOUTS / IOCTL_SERIAL_GET_TIMEOUTS serial redirection: use of winpr-comm's functions and not serial_tty.* anymore --- channels/serial/client/CMakeLists.txt | 3 - channels/serial/client/serial_main.c | 269 +++++++++++++------- winpr/include/winpr/comm.h | 16 ++ winpr/libwinpr/comm/CMakeLists.txt | 1 + winpr/libwinpr/comm/comm.c | 89 ++++++- winpr/libwinpr/comm/comm.h | 1 + winpr/libwinpr/comm/comm_io.c | 316 ++++++++++++++++++++++++ winpr/libwinpr/comm/comm_ioctl.c | 65 ++++- winpr/libwinpr/comm/comm_ioctl.h | 18 +- winpr/libwinpr/comm/comm_sercx2_sys.c | 5 + winpr/libwinpr/comm/comm_sercx_sys.c | 7 +- winpr/libwinpr/comm/comm_serial_sys.c | 34 +++ winpr/libwinpr/comm/test/CMakeLists.txt | 1 + winpr/libwinpr/comm/test/TestTimeouts.c | 126 ++++++++++ 14 files changed, 841 insertions(+), 110 deletions(-) create mode 100644 winpr/libwinpr/comm/comm_io.c create mode 100644 winpr/libwinpr/comm/test/TestTimeouts.c diff --git a/channels/serial/client/CMakeLists.txt b/channels/serial/client/CMakeLists.txt index a919a0180..7d0fe8897 100644 --- a/channels/serial/client/CMakeLists.txt +++ b/channels/serial/client/CMakeLists.txt @@ -18,9 +18,6 @@ define_channel_client("serial") set(${MODULE_PREFIX}_SRCS - serial_tty.c - serial_tty.h - serial_constants.h serial_main.c) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry") diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index c592f607d..e46da4c73 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -42,9 +42,6 @@ #include #endif -#include "serial_tty.h" -#include "serial_constants.h" - #include #include #include @@ -65,11 +62,7 @@ struct _SERIAL_DEVICE DEVICE device; HANDLE* hComm; - // TMP: TBR - char* path; - SERIAL_TTY* tty; - // - + // TMP: use of log wLog* log; HANDLE thread; wMessageQueue* IrpQueue; @@ -77,13 +70,11 @@ struct _SERIAL_DEVICE static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { - UINT32 FileId; - DWORD DesiredAccess; DWORD SharedAccess; DWORD CreateDisposition; UINT32 PathLength; - + Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */ Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ @@ -95,16 +86,37 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */ - /* CommCreateFileA current implementation expects nothing else than that */ - assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE)); - assert(SharedAccess == 0); - assert(CreateDisposition == OPEN_EXISTING); + +#ifndef _WIN32 + /* Windows 2012 server sends on a first call : + * DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES + * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ + * CreateDisposition = 0x00000001: CREATE_NEW + * + * then sends : + * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA + * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ + * CreateDisposition = 0x00000001: CREATE_NEW + * + * assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE)); + * assert(SharedAccess == 0); + * assert(CreateDisposition == OPEN_EXISTING); + * + */ + + DEBUG_SVC("DesiredAccess: 0x%0.8x, SharedAccess: 0x%0.8x, CreateDisposition: 0x%0.8x", DesiredAccess, SharedAccess, CreateDisposition); + + /* FIXME: As of today only the flags below are supported by CommCreateFileA: */ + DesiredAccess = GENERIC_READ | GENERIC_WRITE; + SharedAccess = 0; + CreateDisposition = OPEN_EXISTING; +#endif serial->hComm = CreateFile(serial->device.name, - DesiredAccess, /* GENERIC_READ | GENERIC_WRITE */ - SharedAccess, /* 0 */ + DesiredAccess, + SharedAccess, NULL, /* SecurityAttributes */ - CreateDisposition, /* OPEN_EXISTING */ + CreateDisposition, 0, /* FlagsAndAttributes */ NULL); /* TemplateFile */ @@ -113,17 +125,36 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) DEBUG_WARN("CreateFile failure: %s last-error: Ox%x\n", serial->device.name, GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; - FileId = 0; goto error_handle; } - FileId = irp->devman->id_sequence++; // TMP: !? + /* NOTE: binary mode/raw mode required for the redirection. On + * Linux, CommCreateFileA forces this setting. + */ + /* ZeroMemory(&dcb, sizeof(DCB)); */ + /* dcb.DCBlength = sizeof(DCB); */ + /* GetCommState(serial->hComm, &dcb); */ + /* dcb.fBinary = TRUE; */ + /* SetCommState(serial->hComm, &dcb); */ + + // TMP: + COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = MAXULONG; /* ensures a non blocking state */ + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + SetCommTimeouts(serial->hComm, &timeouts); + + assert(irp->FileId == 0); + irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */ + irp->IoStatus = STATUS_SUCCESS; - DEBUG_SVC("%s %s (%d) created.", serial->device.name, serial->path, FileId); + DEBUG_SVC("%s (DeviceId: %d, FileId: %d) created.", serial->device.name, irp->device->id, irp->FileId); error_handle: - Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */ + Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ irp->Complete(irp); @@ -135,12 +166,12 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) if (!CloseHandle(serial->hComm)) { - DEBUG_WARN("CloseHandle failure: %s %s (%d) closed.", serial->device.name, serial->path, irp->device->id); + DEBUG_WARN("CloseHandle failure: %s (%d) closed.", serial->device.name, irp->device->id); irp->IoStatus = STATUS_UNSUCCESSFUL; goto error_handle; } - DEBUG_SVC("%s %s (%d) closed.", serial->device.name, serial->path, irp->device->id); + DEBUG_SVC("%s (DeviceId: %d, FileId: %d) closed.", serial->device.name, irp->device->id, irp->FileId); serial->hComm = NULL; irp->IoStatus = STATUS_SUCCESS; @@ -156,91 +187,146 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) UINT32 Length; UINT64 Offset; BYTE* buffer = NULL; - SERIAL_TTY* tty = serial->tty; + DWORD nbRead = 0; Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */ Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - if (!tty) - { - irp->IoStatus = STATUS_UNSUCCESSFUL; - Length = 0; - DEBUG_WARN("tty not valid."); + buffer = (BYTE*)calloc(Length, sizeof(BYTE)); + if (buffer == NULL) + { + irp->IoStatus = STATUS_NO_MEMORY; + goto error_handle; + } + + + /* MSRDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored + * assert(Offset == 0); + */ + + + DEBUG_SVC("reading %lu bytes from %s", Length, serial->device.name); + + /* FIXME: CommReadFile to be replaced by ReadFile */ + if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL)) + { + irp->IoStatus = STATUS_SUCCESS; } else { - buffer = (BYTE*) malloc(Length); + DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8x", serial->device.name, nbRead, GetLastError()); - if (!serial_tty_read(tty, buffer, &Length)) + switch(GetLastError()) { - irp->IoStatus = STATUS_UNSUCCESSFUL; - free(buffer); - buffer = NULL; - Length = 0; + case ERROR_INVALID_HANDLE: + irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; + break; - DEBUG_WARN("read %s(%d) failed.", serial->path, tty->id); - } - else - { - DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, tty->id); + case ERROR_NOT_SUPPORTED: + irp->IoStatus = STATUS_NOT_SUPPORTED; + break; + + case ERROR_INVALID_PARAMETER: + irp->IoStatus = STATUS_INVALID_PARAMETER; + break; + + case ERROR_IO_DEVICE: + irp->IoStatus = STATUS_IO_DEVICE_ERROR; + break; + + case ERROR_TIMEOUT: + irp->IoStatus = STATUS_TIMEOUT; + break; + + case ERROR_BAD_DEVICE: + irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + + default: + DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + irp->IoStatus = STATUS_UNSUCCESSFUL; + break; } } - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ + + error_handle: - if (Length > 0) + Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */ + + if (nbRead > 0) { - Stream_EnsureRemainingCapacity(irp->output, Length); - Stream_Write(irp->output, buffer, Length); + Stream_EnsureRemainingCapacity(irp->output, nbRead); + Stream_Write(irp->output, buffer, nbRead); /* ReadData */ } - free(buffer); + + if (buffer) + free(buffer); irp->Complete(irp); } static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) { - int status; UINT32 Length; UINT64 Offset; - SERIAL_TTY* tty = serial->tty; + DWORD nbWritten = 0; Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */ Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - if (!tty) + assert(Offset == 0); /* not implemented otherwise */ + + DEBUG_SVC("writing %lu bytes to %s", Length, serial->device.name); + + /* FIXME: CommWriteFile to be replaced by WriteFile */ + if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten, NULL)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; - Length = 0; + irp->IoStatus = STATUS_SUCCESS; + } + else + { + DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8x", serial->device.name, nbWritten, GetLastError()); - DEBUG_WARN("tty not valid."); + switch(GetLastError()) + { + case ERROR_INVALID_HANDLE: + irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; + break; - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - irp->Complete(irp); - return; + case ERROR_NOT_SUPPORTED: + irp->IoStatus = STATUS_NOT_SUPPORTED; + break; + + case ERROR_INVALID_PARAMETER: + irp->IoStatus = STATUS_INVALID_PARAMETER; + break; + + case ERROR_IO_DEVICE: + irp->IoStatus = STATUS_IO_DEVICE_ERROR; + break; + + case ERROR_TIMEOUT: + irp->IoStatus = STATUS_TIMEOUT; + break; + + case ERROR_BAD_DEVICE: + irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + + default: + DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + irp->IoStatus = STATUS_UNSUCCESSFUL; + break; + } } - status = serial_tty_write(tty, Stream_Pointer(irp->input), Length); - if (status < 0) - { - irp->IoStatus = STATUS_UNSUCCESSFUL; - Length = 0; - - printf("serial_tty_write failure: status: %d, errno: %d\n", status, errno); - - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - irp->Complete(irp); - return; - } - - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ + Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ irp->Complete(irp); } @@ -253,20 +339,12 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) UINT32 OutputBufferLength; BYTE* OutputBuffer = NULL; DWORD BytesReturned = 0; - SERIAL_TTY* tty = serial->tty; Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */ Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */ Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - if (!tty) - { - DEBUG_WARN("tty not valid."); - irp->IoStatus = STATUS_UNSUCCESSFUL; - goto error_handle; - } - OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE)); if (OutputBuffer == NULL) { @@ -280,16 +358,19 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_NO_MEMORY; goto error_handle; } + + Stream_Read(irp->input, InputBuffer, InputBufferLength); + + DEBUG_SVC("CommDeviceIoControl: IoControlCode 0x%x", IoControlCode); - /* FIXME: to be replaced by DeviceIoControl() */ + /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) { - Stream_Write(irp->output, OutputBuffer, BytesReturned); irp->IoStatus = STATUS_SUCCESS; } else { - DEBUG_SVC("CommDeviceIoControl failure: IoControlCode 0x%x last-error: 0x%x", IoControlCode, GetLastError()); + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode 0x%0.8x last-error: 0x%x", IoControlCode, GetLastError()); switch(GetLastError()) { @@ -321,13 +402,25 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) } error_handle: + + Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */ + + if (BytesReturned > 0) + { + Stream_EnsureRemainingCapacity(irp->output, BytesReturned); + Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */ + } + else + { + Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ + } + if (InputBuffer != NULL) free(InputBuffer); if (OutputBuffer != NULL) free(OutputBuffer); - // TMP: double check the completion, Information field irp->Complete(irp); } @@ -402,14 +495,15 @@ static void serial_irp_request(DEVICE* device, IRP* irp) static void serial_free(DEVICE* device) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; - + WLog_Print(serial->log, WLOG_DEBUG, "freeing"); MessageQueue_PostQuit(serial->IrpQueue, 0); WaitForSingleObject(serial->thread, INFINITE); CloseHandle(serial->thread); - serial_tty_free(serial->tty); + if (serial->hComm) + CloseHandle(serial->hComm); /* Clean up resources */ Stream_Free(serial->device.data, TRUE); @@ -442,9 +536,11 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if ((name && name[0]) && (path && path[0])) { + DEBUG_SVC("Defining %s as %s", name, path); + if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) { - DEBUG_SVC("Could not registered: %s as %s", path, name); + DEBUG_SVC("Could not define %s as %s", name, path); return -1; } @@ -463,7 +559,6 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) for (i = 0; i <= len; i++) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); - serial->path = path; serial->IrpQueue = MessageQueue_New(NULL); WLog_Init(); diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 804b8da51..b373fe6f2 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -375,6 +375,11 @@ WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOver /* Extended API */ +/* FIXME: MAXULONG should be defined arround winpr/limits.h */ +#ifndef MAXULONG +#define MAXULONG (4294967295UL) +#endif + /* * About DefineCommDevice() / QueryDosDevice() * @@ -402,6 +407,17 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); +/** + * FIXME: to be moved in comm_io.h + */ +BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); + +/** + * FIXME: to be moved in comm_io.h + */ +BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/CMakeLists.txt b/winpr/libwinpr/comm/CMakeLists.txt index 70f0c6d48..c37af7268 100644 --- a/winpr/libwinpr/comm/CMakeLists.txt +++ b/winpr/libwinpr/comm/CMakeLists.txt @@ -21,6 +21,7 @@ set(MODULE_PREFIX "WINPR_COMM") set(${MODULE_PREFIX}_SRCS comm.c comm.h + comm_io.c comm_ioctl.c comm_ioctl.h comm_serial_sys.c diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index b639c840f..8feb72464 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -522,7 +522,6 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) if (lpDCB->fBinary) { upcomingTermios.c_lflag &= ~ICANON; - // TMP: complete the raw mode here? } else { @@ -563,22 +562,55 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) return TRUE; } +/** + * ERRORS: + * ERROR_INVALID_HANDLE + */ BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; - if (!pComm) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } + + /* as of today, SERIAL_TIMEOUTS and COMMTIMEOUTS structures are identical */ + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, lpCommTimeouts, sizeof(COMMTIMEOUTS), &bytesReturned, NULL)) + { + DEBUG_WARN("GetCommTimeouts failure."); + return FALSE; + } return TRUE; } + +/** + * ERRORS: + * ERROR_INVALID_HANDLE + */ BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; - if (!pComm) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } + + /* as of today, SERIAL_TIMEOUTS and COMMTIMEOUTS structures are identical */ + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_TIMEOUTS, lpCommTimeouts, sizeof(COMMTIMEOUTS), NULL, 0, &bytesReturned, NULL)) + { + DEBUG_WARN("SetCommTimeouts failure."); + return FALSE; + } return TRUE; } @@ -975,7 +1007,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare CHAR devicePath[MAX_PATH]; struct stat deviceStat; WINPR_COMM* pComm = NULL; - + struct termios upcomingTermios; if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE)) { @@ -1052,12 +1084,53 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } + /* Restore the blocking mode for upcoming read/write operations */ + if (fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK) < 0) + { + DEBUG_WARN("failed to open device %s, could not restore the O_NONBLOCK flag", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } - /* TMP: TODO: FIXME: this information is at least need for - * get/set baud. Is possible to pull this information? to be - * forced with a comand line argument. + + /* TMP: TODO: FIXME: this information is at least needed for + * get/set baud functions. Is it possible to pull this + * information? Could be a command line argument. */ - pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; + pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; + + + /* The binary/raw mode is required for the redirection but + * only flags that are not handle somewhere-else, except + * ICANON, are forced here. */ + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } + + upcomingTermios.c_iflag &= ~(/*IGNBRK |*/ BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL /*| IXON*/); + upcomingTermios.c_oflag = 0; /* <=> &= ~OPOST */ + upcomingTermios.c_lflag = 0; /* <=> &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); */ + /* upcomingTermios.c_cflag &= ~(CSIZE | PARENB); */ + /* upcomingTermios.c_cflag |= CS8; */ + + /* About missing missing flags recommended by termios(3) + * + * IGNBRK and IXON, see: IOCTL_SERIAL_SET_HANDFLOW + * CSIZE, PARENB and CS8, see: IOCTL_SERIAL_SET_LINE_CONTROL + */ + + /* a few more settings required for the redirection */ + upcomingTermios.c_cflag |= CLOCAL | CREAD; + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } return (HANDLE)pComm; diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index f77dad7e7..116f85dc4 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -45,6 +45,7 @@ struct winpr_comm int fd; REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; + COMMTIMEOUTS timeouts; /* NB: CloseHandle() has to free resources */ }; diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c new file mode 100644 index 000000000..c25a8b659 --- /dev/null +++ b/winpr/libwinpr/comm/comm_io.c @@ -0,0 +1,316 @@ +/** + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef _WIN32 + +#include +#include +#include + +#include + +#include +#include + +#include "comm.h" + +/* Computes Tmax in deciseconds (m and Tcare in milliseconds) */ +static UCHAR _tmax(DWORD N, ULONG m, ULONG Tc) +{ + /* Tmax = N * m + Tc */ + + ULONGLONG Tmax = N * m + Tc; + + /* FIXME: look for an equivalent math function otherwise let + * do the compiler do the optimization */ + if (Tmax == 0) + return 0; + else if (Tmax < 100) + return 1; + else if (Tmax > 25500) + return 255; /* 0xFF */ + else + return Tmax/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; + ssize_t nbRead = 0; + COMMTIMEOUTS *pTimeouts; + UCHAR vmin = 0; + UCHAR vtime = 0; + struct termios currentTermios; + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (lpOverlapped != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + + if (lpNumberOfBytesRead == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ + return FALSE; + } + + *lpNumberOfBytesRead = 0; /* will be ajusted if required ... */ + + if (nNumberOfBytesToRead <= 0) /* N */ + { + return TRUE; /* FIXME: or FALSE? */ + } + + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (currentTermios.c_lflag & ICANON) + { + DEBUG_WARN("Canonical mode not supported"); /* the timeout could not be set */ + SetLastError(ERROR_NOT_SUPPORTED); + 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 | 0 | Blocks for N bytes available. FIXME: reduce N to 1? + * 0< Ti fd, O_NONBLOCK) doesn't conflict with above use cases + */ + + pTimeouts = &(pComm->timeouts); + + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant == MAXULONG)) + { + DEBUG_WARN("ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* VMIN */ + + if ((pTimeouts->ReadIntervalTimeout < MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + { + /* should only match the two first cases above */ + vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255; /* 0xFF */ + } + + + /* VTIME */ + + if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + { + /* Ti */ + + vtime = _tmax(0, 0, pTimeouts->ReadIntervalTimeout); + + } + else if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant < MAXULONG)) + { + /* Tc */ + + vtime = _tmax(0, 0, pTimeouts->ReadTotalTimeoutConstant); + } + else if ((pTimeouts->ReadTotalTimeoutMultiplier > 0) || (pTimeouts->ReadTotalTimeoutConstant > 0)) /* <=> Tmax > 0 */ + { + /* Tmax and Tmax(1) */ + + vtime = _tmax(nNumberOfBytesToRead, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant); + } + + + if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime)) + { + currentTermios.c_cc[VMIN] = vmin; + currentTermios.c_cc[VTIME] = vtime; + + // TMP: + DEBUG_MSG("Applying timeout VMIN=%u, VTIME=%u", vmin, vtime); + + if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0) + { + DEBUG_WARN("CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + } + + // TMP: + DEBUG_MSG("Reading N=%u, VMIN=%u, VTIME=%u", nNumberOfBytesToRead, vmin, vtime); + + nbRead = read(pComm->fd, lpBuffer, nNumberOfBytesToRead); + + if (nbRead < 0) + { + DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%d, ReadTotalTimeoutMultiplier=%d, ReadTotalTimeoutConstant=%d VMIN=%d, VTIME=%d", + pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, + currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); + DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%d, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); + + switch (errno) + { + // TMP: TODO: + case EAGAIN: /* EWOULDBLOCK */ + nbRead = 0; + break; + + case EBADF: + SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ + return FALSE; + + default: + return FALSE; + } + + } + + // SetLastError(ERROR_TIMEOUT) + + *lpNumberOfBytesRead = nbRead; + 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; + COMMTIMEOUTS *pTimeouts; + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (lpOverlapped != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + + if (lpNumberOfBytesWritten == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ + return FALSE; + } + + *lpNumberOfBytesWritten = 0; /* will be ajusted if required ... */ + + if (nNumberOfBytesToWrite <= 0) + { + return TRUE; /* FIXME: or FALSE? */ + } + + // TMP: TODO: Timeouts + pTimeouts = &(pComm->timeouts); + + while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite) + { + ssize_t nbWritten; + + nbWritten += write(pComm->fd, + lpBuffer + (*lpNumberOfBytesWritten), + nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); + + if (nbWritten < 0) + { + DEBUG_WARN("CommWriteFile failed after %d bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); + + switch (errno) + { + case EAGAIN: + /* EWOULDBLOCK */ + // TMP: FIXME: fcntl(tty->fd, F_SETFL, O_NONBLOCK) and manage the timeout here? + break; + case EBADF: + SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ + return FALSE; + } + + return FALSE; + } + + *lpNumberOfBytesWritten += nbWritten; + } + + + return TRUE; +} + + +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 0b8273a20..346d10f77 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -61,8 +61,10 @@ * * 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) @@ -71,6 +73,12 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe WINPR_COMM* pComm = (WINPR_COMM*) hDevice; REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) { SetLastError(ERROR_INVALID_HANDLE); @@ -85,12 +93,14 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe if (lpBytesReturned == NULL) { - SetLastError(ERROR_INVALID_DATA); /* since we doesn't suppport lpOverlapped != NULL */ + SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ return FALSE; } *lpBytesReturned = 0; /* will be ajusted if required ... */ + DEBUG_MSG("CommDeviceIoControl: IoControlCode: 0x%0.8x", dwIoControlCode); + /* remoteSerialDriver to be use ... * * FIXME: might prefer to use an automatic rather than static structure @@ -111,7 +121,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe case RemoteSerialDriverUnknown: default: - DEBUG_WARN("Unknown remote serial driver (%d), using SerCx2.sys", pComm->remoteSerialDriverId); + DEBUG_MSG("Unknown remote serial driver (%d), using SerCx2.sys", pComm->remoteSerialDriverId); pRemoteSerialDriver = SerCx2Sys_s(); break; } @@ -129,7 +139,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe assert(nInBufferSize >= sizeof(SERIAL_BAUD_RATE)); if (nInBufferSize < sizeof(SERIAL_BAUD_RATE)) { - SetLastError(ERROR_INVALID_DATA); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -188,7 +198,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe assert(nInBufferSize >= sizeof(SERIAL_CHARS)); if (nInBufferSize < sizeof(SERIAL_CHARS)) { - SetLastError(ERROR_INVALID_DATA); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -226,7 +236,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe assert(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL)); if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL)) { - SetLastError(ERROR_INVALID_DATA); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -264,7 +274,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe assert(nInBufferSize >= sizeof(SERIAL_HANDFLOW)); if (nInBufferSize < sizeof(SERIAL_HANDFLOW)) { - SetLastError(ERROR_INVALID_DATA); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -293,10 +303,49 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } + case IOCTL_SERIAL_SET_TIMEOUTS: + { + if (pRemoteSerialDriver->set_timeouts) + { + SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_TIMEOUTS)); + if (nInBufferSize < sizeof(SERIAL_TIMEOUTS)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pRemoteSerialDriver->set_timeouts(pComm, pHandflow); + } + break; + } + case IOCTL_SERIAL_GET_TIMEOUTS: + { + if (pRemoteSerialDriver->get_timeouts) + { + SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS)); + if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_timeouts(pComm, pHandflow)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_TIMEOUTS); + return TRUE; + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } @@ -323,7 +372,7 @@ int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *te if (memcmp(¤tState, &termios_p, sizeof(struct termios)) != 0) { - DEBUG_WARN("all termios parameters were not set, doing a second attempt..."); + DEBUG_MSG("all termios parameters are not set yet, doing a second attempt..."); if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0) { DEBUG_WARN("2nd tcsetattr failure, errno: %d", errno); @@ -339,7 +388,7 @@ int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *te if (memcmp(¤tState, termios_p, sizeof(struct termios)) != 0) { - DEBUG_WARN("Failure: all parameters were not set on a second attempt."); + DEBUG_WARN("Failure: all termios parameters are still not set on a second attempt"); return -1; /* TMP: double-check whether some parameters can differ anyway */ } } diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 5ef8ff407..84261b79b 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -45,9 +45,8 @@ extern "C" { #define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 #define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C #define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 -/* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */ -/* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */ - +#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C +#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 /* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ #define IOCTL_SERIAL_GET_CHARS 0x001B0058 #define IOCTL_SERIAL_SET_CHARS 0x001B005C @@ -179,6 +178,17 @@ typedef struct _SERIAL_HANDFLOW #define SERIAL_SP_TELNET ((ULONG)0x00000102) #define SERIAL_SP_X25 ((ULONG)0x00000103) + +typedef struct _SERIAL_TIMEOUTS +{ + ULONG ReadIntervalTimeout; + ULONG ReadTotalTimeoutMultiplier; + ULONG ReadTotalTimeoutConstant; + ULONG WriteTotalTimeoutMultiplier; + ULONG WriteTotalTimeoutConstant; +} SERIAL_TIMEOUTS,*PSERIAL_TIMEOUTS; + + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -197,6 +207,8 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 7f657f827..1b870eec5 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -66,6 +66,8 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_line_control = NULL, .set_handflow = NULL, .get_handflow = NULL, + .set_timeouts = NULL, + .get_timeouts = NULL, }; @@ -89,6 +91,9 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_handflow = pSerialSys->set_handflow; _SerCx2Sys.get_handflow = pSerialSys->get_handflow; + _SerCx2Sys.set_timeouts = pSerialSys->set_timeouts; + _SerCx2Sys.get_timeouts = pSerialSys->get_timeouts; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 8dad85738..d3276fd8b 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -188,7 +188,7 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%0.8x", GetLastError()); return FALSE; } @@ -507,6 +507,8 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_line_control = NULL, .set_handflow = _set_handflow, .get_handflow = _get_handflow, + .set_timeouts = NULL, + .get_timeouts = NULL, }; @@ -521,6 +523,9 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _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; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index aaf5fe64c..66f95c84d 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -827,6 +827,38 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) return TRUE; } +static BOOL _set_timeouts(WINPR_COMM *pComm, const SERIAL_TIMEOUTS *pTimeouts) +{ + /* NB: timeouts are applied on system during read/write I/O */ + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx */ + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant == MAXULONG)) + { + DEBUG_WARN("ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + pComm->timeouts.ReadIntervalTimeout = pTimeouts->ReadIntervalTimeout; + pComm->timeouts.ReadTotalTimeoutMultiplier = pTimeouts->ReadTotalTimeoutMultiplier; + pComm->timeouts.ReadTotalTimeoutConstant = pTimeouts->ReadTotalTimeoutConstant; + pComm->timeouts.WriteTotalTimeoutMultiplier = pTimeouts->WriteTotalTimeoutMultiplier; + pComm->timeouts.WriteTotalTimeoutConstant = pTimeouts->WriteTotalTimeoutConstant; + + return TRUE; +} + +static BOOL _get_timeouts(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts) +{ + pTimeouts->ReadIntervalTimeout = pComm->timeouts.ReadIntervalTimeout; + pTimeouts->ReadTotalTimeoutMultiplier = pComm->timeouts.ReadTotalTimeoutMultiplier; + pTimeouts->ReadTotalTimeoutConstant = pComm->timeouts.ReadTotalTimeoutConstant; + pTimeouts->WriteTotalTimeoutMultiplier = pComm->timeouts.WriteTotalTimeoutMultiplier; + pTimeouts->WriteTotalTimeoutConstant = pComm->timeouts.WriteTotalTimeoutConstant; + + return TRUE; +} + static REMOTE_SERIAL_DRIVER _SerialSys = { @@ -841,6 +873,8 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_line_control = _get_line_control, .set_handflow = _set_handflow, .get_handflow = _get_handflow, + .set_timeouts = _set_timeouts, + .get_timeouts = _get_timeouts, }; diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt index d81c3228c..dcf737f3a 100644 --- a/winpr/libwinpr/comm/test/CMakeLists.txt +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -12,6 +12,7 @@ set(${MODULE_PREFIX}_TESTS TestSerialChars.c TestControlSettings.c TestHandflow.c + TestTimeouts.c TestCommMonitor.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/comm/test/TestTimeouts.c b/winpr/libwinpr/comm/test/TestTimeouts.c new file mode 100644 index 000000000..4799eb794 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestTimeouts.c @@ -0,0 +1,126 @@ +/** + * 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 +#include + +#include +#include + +#include "../comm.h" + +static BOOL test_generic(HANDLE hComm) +{ + COMMTIMEOUTS timeouts, timeouts2; + + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 2; + timeouts.ReadTotalTimeoutConstant = 3; + timeouts.WriteTotalTimeoutMultiplier = 4; + timeouts.WriteTotalTimeoutConstant = 5; + + if (!SetCommTimeouts(hComm, &timeouts)) + { + fprintf(stderr, "SetCommTimeouts failure, GetLastError: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&timeouts2, sizeof(COMMTIMEOUTS)); + if (!GetCommTimeouts(hComm, &timeouts2)) + { + fprintf(stderr, "GetCommTimeouts failure, GetLastError: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + if (memcmp(&timeouts, &timeouts2, sizeof(COMMTIMEOUTS)) != 0) + { + 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)) + { + fprintf(stderr, "SetCommTimeouts succeeded with ReadIntervalTimeout and ReadTotalTimeoutConstant set to MAXULONG. GetLastError: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + fprintf(stderr, "SetCommTimeouts failure, expected GetLastError to return ERROR_INVALID_PARAMETER and got: 0x%0.8x\n", GetLastError()); + return FALSE; + } + + return TRUE; +} + + +int TestTimeouts(int argc, char* argv[]) +{ + BOOL result; + HANDLE hComm; + + // TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_SerialSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_SerCx2Sys failure\n"); + return EXIT_FAILURE; + } + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} From 7f9545f12e35c78783a88fe64698ba689c14d26a Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 12 May 2014 19:21:06 +0200 Subject: [PATCH 19/61] serial: removed the extra byte sent with an empty OutputBuffer. At least Windows 2008R2 SP1 works better without it. Need to figure out why... --- channels/serial/client/serial_main.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index e46da4c73..70b9c9fc7 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -93,7 +93,7 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ * CreateDisposition = 0x00000001: CREATE_NEW * - * then sends : + * then Windows 2012 sends : * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ * CreateDisposition = 0x00000001: CREATE_NEW @@ -410,10 +410,14 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_EnsureRemainingCapacity(irp->output, BytesReturned); Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */ } - else - { - Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - } + /* TMP: FIXME: Why at least Windows 2008R2 gets lost with this + * extra byte and likely on a IOCTL_SERIAL_SET_BAUD_RATE? The + * extra byte is well required according MS-RDPEFS + * 2.2.1.5.5 */ + /* else */ + /* { */ + /* Stream_Write_UINT8(irp->output, 0); /\* Padding (1 byte) *\/ */ + /* } */ if (InputBuffer != NULL) free(InputBuffer); From 7684ff7bd47abb2b43514556a5989d39c5751d41 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 12 May 2014 20:16:13 +0200 Subject: [PATCH 20/61] winpr-comm: got IOCTL_SERIAL_SET_DTR / IOCTL_SERIAL_CLR_DTR --- winpr/libwinpr/comm/comm_ioctl.c | 17 +++++++++++++- winpr/libwinpr/comm/comm_ioctl.h | 9 +++++--- winpr/libwinpr/comm/comm_sercx2_sys.c | 5 +++++ winpr/libwinpr/comm/comm_sercx_sys.c | 5 +++++ winpr/libwinpr/comm/comm_serial_sys.c | 32 +++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 4 deletions(-) diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 346d10f77..cb55aefbd 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -341,7 +341,22 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } - + case IOCTL_SERIAL_SET_DTR: + { + if (pRemoteSerialDriver->set_dtr) + { + return pRemoteSerialDriver->set_dtr(pComm); + } + break; + } + case IOCTL_SERIAL_CLR_DTR: + { + if (pRemoteSerialDriver->clear_dtr) + { + return pRemoteSerialDriver->clear_dtr(pComm); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 84261b79b..2593ee7ff 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -32,7 +32,8 @@ #include "comm.h" -/* Ntddser.h http://msdn.microsoft.com/en-us/cc308432.aspx +/* 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 */ @@ -51,8 +52,8 @@ extern "C" { #define IOCTL_SERIAL_GET_CHARS 0x001B0058 #define IOCTL_SERIAL_SET_CHARS 0x001B005C -/* IOCTL_SERIAL_SET_DTR 0x001B0024 */ -/* IOCTL_SERIAL_CLR_DTR 0x001B0028 */ +#define IOCTL_SERIAL_SET_DTR 0x001B0024 +#define IOCTL_SERIAL_CLR_DTR 0x001B0028 /* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ /* IOCTL_SERIAL_SET_RTS 0x001B0030 */ /* IOCTL_SERIAL_CLR_RTS 0x001B0034 */ @@ -209,6 +210,8 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 1b870eec5..aa819790a 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -68,6 +68,8 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_handflow = NULL, .set_timeouts = NULL, .get_timeouts = NULL, + .set_dtr = NULL, + .clear_dtr = NULL, }; @@ -94,6 +96,9 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_timeouts = pSerialSys->set_timeouts; _SerCx2Sys.get_timeouts = pSerialSys->get_timeouts; + _SerCx2Sys.set_dtr = pSerialSys->set_dtr; + _SerCx2Sys.clear_dtr = pSerialSys->clear_dtr; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index d3276fd8b..e0593a493 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -509,6 +509,8 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_handflow = _get_handflow, .set_timeouts = NULL, .get_timeouts = NULL, + .set_dtr = NULL, + .clear_dtr = NULL, }; @@ -526,6 +528,9 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.set_timeouts = pSerialSys->set_timeouts; _SerCxSys.get_timeouts = pSerialSys->get_timeouts; + _SerCxSys.set_dtr = pSerialSys->set_dtr; + _SerCxSys.clear_dtr = pSerialSys->clear_dtr; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 66f95c84d..1e75e4ecc 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -22,6 +22,7 @@ #ifndef _WIN32 +#include #include #include @@ -860,6 +861,35 @@ static BOOL _get_timeouts(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts) } +static BOOL _set_line(WINPR_COMM *pComm, UINT32 line) +{ + ioctl(pComm->fd, TIOCMBIS, line); + return TRUE; +} + + +static BOOL _clear_line(WINPR_COMM *pComm, UINT32 line) +{ + ioctl(pComm->fd, TIOCMBIC, line); + return TRUE; +} + + +static BOOL _set_dtr(WINPR_COMM *pComm) +{ + /* FIXME: SERIAL_DTR_HANDSHAKE should be checked but is not supported as of today */ + + return _set_line(pComm, TIOCM_DTR); +} + +static BOOL _clear_dtr(WINPR_COMM *pComm) +{ + /* FIXME: SERIAL_DTR_HANDSHAKE should be checked but is not supported as of today */ + + return _clear_line(pComm, TIOCM_DTR); +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -875,6 +905,8 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_handflow = _get_handflow, .set_timeouts = _set_timeouts, .get_timeouts = _get_timeouts, + .set_dtr = _set_dtr, + .clear_dtr = _clear_dtr, }; From 881370a338bafbaf938e4be8de948bb4d63ffe85 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 12 May 2014 20:33:33 +0200 Subject: [PATCH 21/61] winpr-comm: got IOCTL_SERIAL_SET_RTS / IOCTL_SERIAL_CLR_RTS --- winpr/libwinpr/comm/comm_ioctl.c | 16 ++++++++ winpr/libwinpr/comm/comm_ioctl.h | 6 ++- winpr/libwinpr/comm/comm_sercx2_sys.c | 5 +++ winpr/libwinpr/comm/comm_sercx_sys.c | 5 +++ winpr/libwinpr/comm/comm_serial_sys.c | 59 ++++++++++++++++++++++++++- 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index cb55aefbd..6002fc764 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -357,6 +357,22 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } + case IOCTL_SERIAL_SET_RTS: + { + if (pRemoteSerialDriver->set_rts) + { + return pRemoteSerialDriver->set_rts(pComm); + } + break; + } + case IOCTL_SERIAL_CLR_RTS: + { + if (pRemoteSerialDriver->clear_rts) + { + return pRemoteSerialDriver->clear_rts(pComm); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 2593ee7ff..29d0ede8d 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -55,8 +55,8 @@ extern "C" { #define IOCTL_SERIAL_SET_DTR 0x001B0024 #define IOCTL_SERIAL_CLR_DTR 0x001B0028 /* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ -/* IOCTL_SERIAL_SET_RTS 0x001B0030 */ -/* IOCTL_SERIAL_CLR_RTS 0x001B0034 */ +#define IOCTL_SERIAL_SET_RTS 0x001B0030 +#define IOCTL_SERIAL_CLR_RTS 0x001B0034 /* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ /* IOCTL_SERIAL_SET_XON 0x001B003C */ /* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ @@ -212,6 +212,8 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index aa819790a..d1e05b4b3 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -70,6 +70,8 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_timeouts = NULL, .set_dtr = NULL, .clear_dtr = NULL, + .set_rts = NULL, + .clear_rts = NULL, }; @@ -99,6 +101,9 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_dtr = pSerialSys->set_dtr; _SerCx2Sys.clear_dtr = pSerialSys->clear_dtr; + _SerCx2Sys.set_rts = pSerialSys->set_rts; + _SerCx2Sys.clear_rts = pSerialSys->clear_rts; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index e0593a493..1004d6fd0 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -511,6 +511,8 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_timeouts = NULL, .set_dtr = NULL, .clear_dtr = NULL, + .set_rts = NULL, + .clear_rts = NULL, }; @@ -531,6 +533,9 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.set_dtr = pSerialSys->set_dtr; _SerCxSys.clear_dtr = pSerialSys->clear_dtr; + _SerCxSys.set_rts = pSerialSys->set_rts; + _SerCxSys.clear_rts = pSerialSys->clear_rts; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 1e75e4ecc..20572af5b 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -22,6 +22,7 @@ #ifndef _WIN32 +#include #include #include @@ -877,18 +878,70 @@ static BOOL _clear_line(WINPR_COMM *pComm, UINT32 line) static BOOL _set_dtr(WINPR_COMM *pComm) { - /* FIXME: SERIAL_DTR_HANDSHAKE should be checked but is not supported as of today */ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + /* SERIAL_DTR_HANDSHAKE not supported as of today */ + assert((handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) == 0); + + if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } return _set_line(pComm, TIOCM_DTR); } static BOOL _clear_dtr(WINPR_COMM *pComm) { - /* FIXME: SERIAL_DTR_HANDSHAKE should be checked but is not supported as of today */ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + /* SERIAL_DTR_HANDSHAKE not supported as of today */ + assert((handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) == 0); + + if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } return _clear_line(pComm, TIOCM_DTR); } +static BOOL _set_rts(WINPR_COMM *pComm) +{ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return _set_line(pComm, TIOCM_RTS); +} + +static BOOL _clear_rts(WINPR_COMM *pComm) +{ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return _clear_line(pComm, TIOCM_RTS); +} + static REMOTE_SERIAL_DRIVER _SerialSys = { @@ -907,6 +960,8 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_timeouts = _get_timeouts, .set_dtr = _set_dtr, .clear_dtr = _clear_dtr, + .set_rts = _set_rts, + .clear_rts = _clear_rts, }; From 7e36374a89c10b265b0690e938d076d248bd0b1d Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 13 May 2014 14:55:30 +0200 Subject: [PATCH 22/61] serial: attempt to use two additional threads for read and write requests winpr-comm: fixed CommWriteFile --- channels/serial/client/serial_main.c | 154 ++++++++++++++++++++++++--- winpr/libwinpr/comm/comm_io.c | 11 +- 2 files changed, 142 insertions(+), 23 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 70b9c9fc7..65b1b7dc7 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -64,8 +64,14 @@ struct _SERIAL_DEVICE // TMP: use of log wLog* log; - HANDLE thread; - wMessageQueue* IrpQueue; + HANDLE MainThread; + wMessageQueue* MainIrpQueue; + + HANDLE ReadThread; + wMessageQueue* ReadIrpQueue; + + HANDLE WriteThread; + wMessageQueue* WriteIrpQueue; }; static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) @@ -262,7 +268,6 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) Stream_Write(irp->output, buffer, nbRead); /* ReadData */ } - if (buffer) free(buffer); @@ -325,6 +330,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) } } + DEBUG_SVC("%lu bytes written to %s", nbWritten, serial->device.name); Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ @@ -463,18 +469,18 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) } } -static void* serial_thread_func(void* arg) +static void* serial_read_thread_func(void* arg) { IRP* irp; wMessage message; - SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; while (1) { - if (!MessageQueue_Wait(drive->IrpQueue)) + if (!MessageQueue_Wait(serial->ReadIrpQueue)) break; - if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE)) + if (!MessageQueue_Peek(serial->ReadIrpQueue, &message, TRUE)) break; if (message.id == WMQ_QUIT) @@ -483,7 +489,68 @@ static void* serial_thread_func(void* arg) irp = (IRP*) message.wParam; if (irp) - serial_process_irp(drive, irp); + { + assert(irp->MajorFunction == IRP_MJ_READ); + serial_process_irp(serial, irp); + } + } + + ExitThread(0); + return NULL; +} + +static void* serial_write_thread_func(void* arg) +{ + IRP* irp; + wMessage message; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; + + while (1) + { + if (!MessageQueue_Wait(serial->WriteIrpQueue)) + break; + + if (!MessageQueue_Peek(serial->WriteIrpQueue, &message, TRUE)) + break; + + if (message.id == WMQ_QUIT) + break; + + irp = (IRP*) message.wParam; + + if (irp) + { + assert(irp->MajorFunction == IRP_MJ_WRITE); + serial_process_irp(serial, irp); + } + } + + ExitThread(0); + return NULL; +} + + +static void* serial_thread_func(void* arg) +{ + IRP* irp; + wMessage message; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; + + while (1) + { + if (!MessageQueue_Wait(serial->MainIrpQueue)) + break; + + if (!MessageQueue_Peek(serial->MainIrpQueue, &message, TRUE)) + break; + + if (message.id == WMQ_QUIT) + break; + + irp = (IRP*) message.wParam; + + if (irp) + serial_process_irp(serial, irp); } ExitThread(0); @@ -493,7 +560,30 @@ static void* serial_thread_func(void* arg) static void serial_irp_request(DEVICE* device, IRP* irp) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; - MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL); + + assert(irp != NULL); + + if (irp == NULL) + return; + + /* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this + * allows the server to send multiple simultaneous read or + * write requests. + */ + + switch(irp->MajorFunction) + { + case IRP_MJ_READ: + MessageQueue_Post(serial->ReadIrpQueue, NULL, 0, (void*) irp, NULL); + break; + + case IRP_MJ_WRITE: + MessageQueue_Post(serial->WriteIrpQueue, NULL, 0, (void*) irp, NULL); + break; + + default: + MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); + } } static void serial_free(DEVICE* device) @@ -502,16 +592,28 @@ static void serial_free(DEVICE* device) WLog_Print(serial->log, WLOG_DEBUG, "freeing"); - MessageQueue_PostQuit(serial->IrpQueue, 0); - WaitForSingleObject(serial->thread, INFINITE); - CloseHandle(serial->thread); + /* TMP: FIXME: also send a signal to interrupt I/O */ + + MessageQueue_PostQuit(serial->ReadIrpQueue, 0); + WaitForSingleObject(serial->ReadThread, INFINITE); + CloseHandle(serial->ReadThread); + + MessageQueue_PostQuit(serial->WriteIrpQueue, 0); + WaitForSingleObject(serial->WriteThread, INFINITE); + CloseHandle(serial->WriteThread); + + MessageQueue_PostQuit(serial->MainIrpQueue, 0); + WaitForSingleObject(serial->MainThread, INFINITE); + CloseHandle(serial->MainThread); if (serial->hComm) CloseHandle(serial->hComm); /* Clean up resources */ Stream_Free(serial->device.data, TRUE); - MessageQueue_Free(serial->IrpQueue); + MessageQueue_Free(serial->ReadIrpQueue); + MessageQueue_Free(serial->WriteIrpQueue); + MessageQueue_Free(serial->MainIrpQueue); free(serial); } @@ -563,7 +665,9 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) for (i = 0; i <= len; i++) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); - serial->IrpQueue = MessageQueue_New(NULL); + serial->ReadIrpQueue = MessageQueue_New(NULL); + serial->WriteIrpQueue = MessageQueue_New(NULL); + serial->MainIrpQueue = MessageQueue_New(NULL); WLog_Init(); serial->log = WLog_Get("com.freerdp.channel.serial.client"); @@ -571,8 +675,26 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); - serial->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); + serial->ReadThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE) serial_read_thread_func, + (void*) serial, + 0, + NULL); + + serial->WriteThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE) serial_write_thread_func, + (void*) serial, + 0, + NULL); + + serial->MainThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE) serial_thread_func, + (void*) serial, + 0, + NULL); } return 0; diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index c25a8b659..ed42fc50e 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -196,9 +196,6 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } } - // TMP: - DEBUG_MSG("Reading N=%u, VMIN=%u, VTIME=%u", nNumberOfBytesToRead, vmin, vtime); - nbRead = read(pComm->fd, lpBuffer, nNumberOfBytesToRead); if (nbRead < 0) @@ -225,6 +222,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } + // TODO: // SetLastError(ERROR_TIMEOUT) *lpNumberOfBytesRead = nbRead; @@ -283,9 +281,9 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite { ssize_t nbWritten; - nbWritten += write(pComm->fd, - lpBuffer + (*lpNumberOfBytesWritten), - nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); + nbWritten = write(pComm->fd, + lpBuffer + (*lpNumberOfBytesWritten), + nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); if (nbWritten < 0) { @@ -308,7 +306,6 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite *lpNumberOfBytesWritten += nbWritten; } - return TRUE; } From 7ec15d968304346af4cbd2076694648defa8dc17 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 13 May 2014 15:12:14 +0200 Subject: [PATCH 23/61] serial: removed the Write thread (kept the read and main threads) serial: better closing --- channels/serial/client/serial_main.c | 55 +--------------------------- 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 65b1b7dc7..c2c41a285 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -69,9 +69,6 @@ struct _SERIAL_DEVICE HANDLE ReadThread; wMessageQueue* ReadIrpQueue; - - HANDLE WriteThread; - wMessageQueue* WriteIrpQueue; }; static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) @@ -499,37 +496,6 @@ static void* serial_read_thread_func(void* arg) return NULL; } -static void* serial_write_thread_func(void* arg) -{ - IRP* irp; - wMessage message; - SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; - - while (1) - { - if (!MessageQueue_Wait(serial->WriteIrpQueue)) - break; - - if (!MessageQueue_Peek(serial->WriteIrpQueue, &message, TRUE)) - break; - - if (message.id == WMQ_QUIT) - break; - - irp = (IRP*) message.wParam; - - if (irp) - { - assert(irp->MajorFunction == IRP_MJ_WRITE); - serial_process_irp(serial, irp); - } - } - - ExitThread(0); - return NULL; -} - - static void* serial_thread_func(void* arg) { IRP* irp; @@ -577,10 +543,6 @@ static void serial_irp_request(DEVICE* device, IRP* irp) MessageQueue_Post(serial->ReadIrpQueue, NULL, 0, (void*) irp, NULL); break; - case IRP_MJ_WRITE: - MessageQueue_Post(serial->WriteIrpQueue, NULL, 0, (void*) irp, NULL); - break; - default: MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); } @@ -592,16 +554,10 @@ static void serial_free(DEVICE* device) WLog_Print(serial->log, WLOG_DEBUG, "freeing"); - /* TMP: FIXME: also send a signal to interrupt I/O */ - MessageQueue_PostQuit(serial->ReadIrpQueue, 0); - WaitForSingleObject(serial->ReadThread, INFINITE); + WaitForSingleObject(serial->ReadThread, 100 /* ms */); /* INFINITE might block on a read, FIXME: is a better signal possible? */ CloseHandle(serial->ReadThread); - MessageQueue_PostQuit(serial->WriteIrpQueue, 0); - WaitForSingleObject(serial->WriteThread, INFINITE); - CloseHandle(serial->WriteThread); - MessageQueue_PostQuit(serial->MainIrpQueue, 0); WaitForSingleObject(serial->MainThread, INFINITE); CloseHandle(serial->MainThread); @@ -612,7 +568,6 @@ static void serial_free(DEVICE* device) /* Clean up resources */ Stream_Free(serial->device.data, TRUE); MessageQueue_Free(serial->ReadIrpQueue); - MessageQueue_Free(serial->WriteIrpQueue); MessageQueue_Free(serial->MainIrpQueue); free(serial); @@ -666,7 +621,6 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); serial->ReadIrpQueue = MessageQueue_New(NULL); - serial->WriteIrpQueue = MessageQueue_New(NULL); serial->MainIrpQueue = MessageQueue_New(NULL); WLog_Init(); @@ -682,13 +636,6 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) 0, NULL); - serial->WriteThread = CreateThread(NULL, - 0, - (LPTHREAD_START_ROUTINE) serial_write_thread_func, - (void*) serial, - 0, - NULL); - serial->MainThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) serial_thread_func, From 116995f8653406a207673a92424a63890609e076 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 13 May 2014 17:27:51 +0200 Subject: [PATCH 24/61] wimpr-comm: got IOCTL_SERIAL_GET_MODEMSTATUS --- channels/serial/client/serial_main.c | 4 ++-- winpr/libwinpr/comm/comm_ioctl.c | 21 ++++++++++++++++++ winpr/libwinpr/comm/comm_ioctl.h | 13 ++++++++++- winpr/libwinpr/comm/comm_sercx2_sys.c | 3 +++ winpr/libwinpr/comm/comm_sercx_sys.c | 3 +++ winpr/libwinpr/comm/comm_serial_sys.c | 31 +++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 3 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index c2c41a285..98e84d5a4 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -555,11 +555,11 @@ static void serial_free(DEVICE* device) WLog_Print(serial->log, WLOG_DEBUG, "freeing"); MessageQueue_PostQuit(serial->ReadIrpQueue, 0); - WaitForSingleObject(serial->ReadThread, 100 /* ms */); /* INFINITE might block on a read, FIXME: is a better signal possible? */ + WaitForSingleObject(serial->ReadThread, 100 /* ms */); /* INFINITE can block the process on a Read, FIXME: is a better signal possible? */ CloseHandle(serial->ReadThread); MessageQueue_PostQuit(serial->MainIrpQueue, 0); - WaitForSingleObject(serial->MainThread, INFINITE); + WaitForSingleObject(serial->MainThread, INFINITE); /* FIXME: might likely block on a pending Write or ioctl */ CloseHandle(serial->MainThread); if (serial->hComm) diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 6002fc764..89de82871 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -373,6 +373,27 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } + case IOCTL_SERIAL_GET_MODEMSTATUS: + { + if (pRemoteSerialDriver->get_modemstatus) + { + ULONG *pRegister = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_modemstatus(pComm, pRegister)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 29d0ede8d..8ae137fc6 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -69,7 +69,7 @@ extern "C" { /* IOCTL_SERIAL_PURGE 0x001B004C */ #define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 #define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 -/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */ +#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 /* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ /* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ #define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 @@ -190,6 +190,16 @@ typedef struct _SERIAL_TIMEOUTS } 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 + + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -214,6 +224,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index d1e05b4b3..517430c6d 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -72,6 +72,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .clear_dtr = NULL, .set_rts = NULL, .clear_rts = NULL, + .get_modemstatus = NULL, }; @@ -104,6 +105,8 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_rts = pSerialSys->set_rts; _SerCx2Sys.clear_rts = pSerialSys->clear_rts; + _SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 1004d6fd0..fef0339f2 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -513,6 +513,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .clear_dtr = NULL, .set_rts = NULL, .clear_rts = NULL, + .get_modemstatus = NULL, }; @@ -536,6 +537,8 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.set_rts = pSerialSys->set_rts; _SerCxSys.clear_rts = pSerialSys->clear_rts; + _SerCxSys.get_modemstatus = pSerialSys->get_modemstatus; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 20572af5b..cdc5d6486 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -943,6 +943,36 @@ static BOOL _clear_rts(WINPR_COMM *pComm) } + +static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) +{ + UINT32 lines=0; + ioctl(pComm->fd, TIOCMGET, &lines); + + ZeroMemory(pRegister, sizeof(ULONG)); + + /* TODO: FIXME: how to get a direct access from the user space + * to the MSR register in order to complete the 4 first bits? + */ + + /* #define SERIAL_MSR_DCTS 0x01 */ + /* #define SERIAL_MSR_DDSR 0x02 */ + /* #define SERIAL_MSR_TERI 0x04 */ + /* #define SERIAL_MSR_DDCD 0x08 */ + + if (lines & TIOCM_CTS) + *pRegister |= SERIAL_MSR_CTS; + if (lines & TIOCM_DSR) + *pRegister |= SERIAL_MSR_DSR; + if (lines & TIOCM_RI) + *pRegister |= SERIAL_MSR_RI; + if (lines & TIOCM_CD) + *pRegister |= SERIAL_MSR_DCD; + + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -962,6 +992,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .clear_dtr = _clear_dtr, .set_rts = _set_rts, .clear_rts = _clear_rts, + .get_modemstatus = _get_modemstatus, }; From 4243928c2e348789fd0024df49751206c6362d8a Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 14 May 2014 16:29:10 +0200 Subject: [PATCH 25/61] winpr-comm: fixed _set_lines() / _clear_lines() winpr-comm: got IOCTL_SERIAL_SET_WAIT_MASK / IOCTL_SERIAL_GET_WAIT_MASK and a non-blocking version of IOCTL_SERIAL_WAIT_ON_MASK --- channels/serial/client/serial_main.c | 14 +- winpr/include/winpr/comm.h | 123 ++++++++++ winpr/libwinpr/comm/comm.c | 12 + winpr/libwinpr/comm/comm.h | 6 + winpr/libwinpr/comm/comm_ioctl.c | 83 ++++++- winpr/libwinpr/comm/comm_ioctl.h | 70 ++---- winpr/libwinpr/comm/comm_sercx2_sys.c | 48 ++++ winpr/libwinpr/comm/comm_sercx_sys.c | 44 ++++ winpr/libwinpr/comm/comm_serial_sys.c | 328 ++++++++++++++++++++++++-- 9 files changed, 645 insertions(+), 83 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 98e84d5a4..1b366c9d1 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -364,7 +364,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_Read(irp->input, InputBuffer, InputBufferLength); - DEBUG_SVC("CommDeviceIoControl: IoControlCode 0x%x", IoControlCode); + DEBUG_SVC("CommDeviceIoControl: IoControlCode=[0x%x] %s", IoControlCode, _comm_serial_ioctl_name(IoControlCode)); /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) @@ -373,7 +373,10 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("CommDeviceIoControl failure: IoControlCode 0x%0.8x last-error: 0x%x", IoControlCode, GetLastError()); + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%x", + IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); + + // TMP: TODO: Status code to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests switch(GetLastError()) { @@ -397,9 +400,14 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_NOT_IMPLEMENTED; break; + case ERROR_IO_PENDING: + irp->IoStatus = STATUS_PENDING; + break; + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); - irp->IoStatus = STATUS_UNSUCCESSFUL; + //irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = STATUS_CANCELLED; break; } } diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index b373fe6f2..ed79b4c0f 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -401,6 +401,129 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 +#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 +#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C +#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 +#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C +#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 +/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ +#define IOCTL_SERIAL_GET_CHARS 0x001B0058 +#define IOCTL_SERIAL_SET_CHARS 0x001B005C + +#define IOCTL_SERIAL_SET_DTR 0x001B0024 +#define IOCTL_SERIAL_CLR_DTR 0x001B0028 +/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ +#define IOCTL_SERIAL_SET_RTS 0x001B0030 +#define IOCTL_SERIAL_CLR_RTS 0x001B0034 +/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ +/* IOCTL_SERIAL_SET_XON 0x001B003C */ +/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ +/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ +/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */ +#define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 +#define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 +#define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 +/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ +/* IOCTL_SERIAL_PURGE 0x001B004C */ +#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 +#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 +#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 +/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ +/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ +#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 +/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ +/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ +/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */ +/* IOCTL_SERIAL_GET_STATS 0x001B008C */ +/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ +/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ +/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */ +/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */ + +/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */ +/* IOCTL_PAR_SET_INFORMATION 0x00160008 */ +/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */ +/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */ +/* IOCTL_IEEE1284_GET_MODE 0x00160014 */ +/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */ +/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */ +/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */ +/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */ +/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */ +/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ +/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ + + +typedef struct __SERIAL_IOCTL_NAME +{ + ULONG number; + const char* name; +} _SERIAL_IOCTL_NAME; + +static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = +{ + {IOCTL_SERIAL_SET_BAUD_RATE, "IOCTL_SERIAL_SET_BAUD_RATE"}, + {IOCTL_SERIAL_GET_BAUD_RATE, "IOCTL_SERIAL_GET_BAUD_RATE"}, + {IOCTL_SERIAL_SET_LINE_CONTROL, "IOCTL_SERIAL_SET_LINE_CONTROL"}, + {IOCTL_SERIAL_GET_LINE_CONTROL, "IOCTL_SERIAL_GET_LINE_CONTROL"}, + {IOCTL_SERIAL_SET_TIMEOUTS, "IOCTL_SERIAL_SET_TIMEOUTS"}, + {IOCTL_SERIAL_GET_TIMEOUTS, "IOCTL_SERIAL_GET_TIMEOUTS"}, + {IOCTL_SERIAL_GET_CHARS, "IOCTL_SERIAL_GET_CHARS"}, + {IOCTL_SERIAL_SET_CHARS, "IOCTL_SERIAL_SET_CHARS"}, + {IOCTL_SERIAL_SET_DTR, "IOCTL_SERIAL_SET_DTR"}, + {IOCTL_SERIAL_CLR_DTR, "IOCTL_SERIAL_CLR_DTR"}, + // {IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"}, + {IOCTL_SERIAL_SET_RTS, "IOCTL_SERIAL_SET_RTS"}, + {IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"}, + // {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"}, + // {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"}, + // {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"}, + // {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"}, + // {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"}, + {IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"}, + {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, + {IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"}, + // {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, + // {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"}, + {IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"}, + {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, + {IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"}, + // {IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"}, + // {IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"}, + {IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"}, + // {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"}, + // {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"}, + // {IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"}, + // {IOCTL_SERIAL_GET_STATS, "IOCTL_SERIAL_GET_STATS"}, + // {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"}; + // {IOCTL_SERIAL_GET_MODEM_CONTROL,"IOCTL_SERIAL_GET_MODEM_CONTROL"}, + // {IOCTL_SERIAL_SET_MODEM_CONTROL,"IOCTL_SERIAL_SET_MODEM_CONTROL"}, + // {IOCTL_SERIAL_SET_FIFO_CONTROL, "IOCTL_SERIAL_SET_FIFO_CONTROL"}, + + // {IOCTL_PAR_QUERY_INFORMATION, "IOCTL_PAR_QUERY_INFORMATION"}, + // {IOCTL_PAR_SET_INFORMATION, "IOCTL_PAR_SET_INFORMATION"}, + // {IOCTL_PAR_QUERY_DEVICE_ID, "IOCTL_PAR_QUERY_DEVICE_ID"}, + // {IOCTL_PAR_QUERY_DEVICE_ID_SIZE,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE"}, + // {IOCTL_IEEE1284_GET_MODE, "IOCTL_IEEE1284_GET_MODE"}, + // {IOCTL_IEEE1284_NEGOTIATE, "IOCTL_IEEE1284_NEGOTIATE"}, + // {IOCTL_PAR_SET_WRITE_ADDRESS, "IOCTL_PAR_SET_WRITE_ADDRESS"}, + // {IOCTL_PAR_SET_READ_ADDRESS, "IOCTL_PAR_SET_READ_ADDRESS"}, + // {IOCTL_PAR_GET_DEVICE_CAPS, "IOCTL_PAR_GET_DEVICE_CAPS"}, + // {IOCTL_PAR_GET_DEFAULT_MODES, "IOCTL_PAR_GET_DEFAULT_MODES"}, + // {IOCTL_PAR_QUERY_RAW_DEVICE_ID, "IOCTL_PAR_QUERY_RAW_DEVICE_ID"}, + // {IOCTL_PAR_IS_PORT_FREE, "IOCTL_PAR_IS_PORT_FREE"}, + + {0, NULL} +}; + +/** + * FIXME: got a proper function name and place + */ +const char* _comm_serial_ioctl_name(ULONG number); + + /** * FIXME: to be moved in comm_ioctl.h */ diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 8feb72464..f594fb377 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -27,6 +27,7 @@ #ifndef _WIN32 #include +#include #include #include #include @@ -1099,6 +1100,17 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare */ pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; + if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0) + { + DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } + + + + + /* The binary/raw mode is required for the redirection but * only flags that are not handle somewhere-else, except diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 116f85dc4..272eaa5bc 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -23,6 +23,8 @@ #ifndef _WIN32 +#include + #include #include "../handle/handle.h" @@ -46,6 +48,10 @@ struct winpr_comm int fd; REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; COMMTIMEOUTS timeouts; + + struct serial_icounter_struct counters; + ULONG waitMask; + ULONG pendingEvents; /* NB: CloseHandle() has to free resources */ }; diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 89de82871..8583fa8d3 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -56,9 +56,27 @@ */ +const char* _comm_serial_ioctl_name(ULONG number) +{ + int i; + + for (i=0; _SERIAL_IOCTL_NAMES[i].number != 0; i++) + { + if (_SERIAL_IOCTL_NAMES[i].number == number) + { + return _SERIAL_IOCTL_NAMES[i].name; + } + } + + return "(unknown ioctl name)"; +} + + /** * 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 @@ -73,6 +91,9 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe WINPR_COMM* pComm = (WINPR_COMM*) hDevice; REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; + /* clear any previous last error */ + SetLastError(ERROR_SUCCESS); + if (hDevice == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); @@ -394,9 +415,69 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } + case IOCTL_SERIAL_SET_WAIT_MASK: + { + if (pRemoteSerialDriver->set_wait_mask) + { + ULONG *pWaitMask = (ULONG*)lpInBuffer; + + assert(nInBufferSize >= sizeof(ULONG)); + if (nInBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pRemoteSerialDriver->set_wait_mask(pComm, pWaitMask); + } + break; + } + case IOCTL_SERIAL_GET_WAIT_MASK: + { + if (pRemoteSerialDriver->get_wait_mask) + { + ULONG *pWaitMask = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_wait_mask(pComm, pWaitMask)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + } + case IOCTL_SERIAL_WAIT_ON_MASK: + { + if (pRemoteSerialDriver->wait_on_mask) + { + ULONG *pOutputMask = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->wait_on_mask(pComm, pOutputMask)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + } } - DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); + DEBUG_WARN(_T("unsupported IoControlCode=[Ox%0.8x] %s (remote serial driver: %s)"), + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 8ae137fc6..3c582edde 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -42,59 +42,6 @@ extern "C" { #endif -#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 -#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 -#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C -#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 -#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C -#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 -/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ -#define IOCTL_SERIAL_GET_CHARS 0x001B0058 -#define IOCTL_SERIAL_SET_CHARS 0x001B005C - -#define IOCTL_SERIAL_SET_DTR 0x001B0024 -#define IOCTL_SERIAL_CLR_DTR 0x001B0028 -/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ -#define IOCTL_SERIAL_SET_RTS 0x001B0030 -#define IOCTL_SERIAL_CLR_RTS 0x001B0034 -/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ -/* IOCTL_SERIAL_SET_XON 0x001B003C */ -/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ -/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ -/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */ -/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */ -/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */ -/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */ -/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ -/* IOCTL_SERIAL_PURGE 0x001B004C */ -#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 -#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 -#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 -/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ -/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ -#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 -/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ -/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ -/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */ -/* IOCTL_SERIAL_GET_STATS 0x001B008C */ -/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ -/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ -/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */ -/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */ - -/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */ -/* IOCTL_PAR_SET_INFORMATION 0x00160008 */ -/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */ -/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */ -/* IOCTL_IEEE1284_GET_MODE 0x00160014 */ -/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */ -/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */ -/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */ -/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */ -/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */ -/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ -/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ - #define STOP_BIT_1 0 #define STOP_BITS_1_5 1 @@ -200,6 +147,20 @@ typedef struct _SERIAL_TIMEOUTS #define SERIAL_MSR_DCD 0x80 +#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 + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -225,6 +186,9 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 517430c6d..04e9960a3 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -22,6 +22,8 @@ #ifndef _WIN32 +#include + #include "comm_serial_sys.h" #include "comm_sercx_sys.h" @@ -52,6 +54,45 @@ static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars) } +/* 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) +{ + ULONG possibleMask; + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + possibleMask = *pWaitMask & _SERCX2_SYS_SUPPORTED_EV_MASK; + + if (possibleMask != *pWaitMask) + { + DEBUG_WARN("Not all wait events supported (SerCx2.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask); + + /* FIXME: shall we really set the possibleMask and return FALSE? */ + pComm->waitMask = 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 REMOTE_SERIAL_DRIVER _SerCx2Sys = { @@ -73,6 +114,9 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .set_rts = NULL, .clear_rts = NULL, .get_modemstatus = NULL, + .set_wait_mask = _set_wait_mask, + .get_wait_mask = NULL, + .wait_on_mask = NULL, }; @@ -107,6 +151,10 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _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; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index fef0339f2..c00357eda 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -492,6 +492,43 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) } +/* 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) +{ + ULONG possibleMask; + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK; + + if (possibleMask != *pWaitMask) + { + DEBUG_WARN("Not all wait events supported (SerCx.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask); + + /* FIXME: shall we really set the possibleMask and return FALSE? */ + pComm->waitMask = 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 REMOTE_SERIAL_DRIVER _SerCxSys = @@ -514,6 +551,9 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .set_rts = NULL, .clear_rts = NULL, .get_modemstatus = NULL, + .set_wait_mask = _set_wait_mask, + .get_wait_mask = NULL, + .wait_on_mask = NULL, }; @@ -539,6 +579,10 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _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; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index cdc5d6486..ca004233f 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -23,6 +23,7 @@ #ifndef _WIN32 #include +#include #include #include @@ -140,6 +141,7 @@ static const speed_t _SERIAL_SYS_BAUD_TABLE[][2] = { #define _SERIAL_MAX_BAUD B115200 + static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) { int i; @@ -559,6 +561,7 @@ static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineContr /* hard-coded in N_TTY */ #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ #define TTY_THRESHOLD_UNTHROTTLE 128 +#define N_TTY_BUF_SIZE 4096 static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) { @@ -862,16 +865,28 @@ static BOOL _get_timeouts(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts) } -static BOOL _set_line(WINPR_COMM *pComm, UINT32 line) +static BOOL _set_lines(WINPR_COMM *pComm, UINT32 lines) { - ioctl(pComm->fd, TIOCMBIS, line); + if (ioctl(pComm->fd, TIOCMBIS, &lines) < 0) + { + DEBUG_WARN("TIOCMBIS ioctl failed, lines=0x%0.4X, errno=[%d] %s", lines, errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + return TRUE; } -static BOOL _clear_line(WINPR_COMM *pComm, UINT32 line) +static BOOL _clear_lines(WINPR_COMM *pComm, UINT32 lines) { - ioctl(pComm->fd, TIOCMBIC, line); + if (ioctl(pComm->fd, TIOCMBIC, &lines) < 0) + { + DEBUG_WARN("TIOCMBIC ioctl failed, lines=0x%0.4X, errno=[%d] %s", lines, errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + return TRUE; } @@ -891,7 +906,7 @@ static BOOL _set_dtr(WINPR_COMM *pComm) return FALSE; } - return _set_line(pComm, TIOCM_DTR); + return _set_lines(pComm, TIOCM_DTR); } static BOOL _clear_dtr(WINPR_COMM *pComm) @@ -909,37 +924,39 @@ static BOOL _clear_dtr(WINPR_COMM *pComm) return FALSE; } - return _clear_line(pComm, TIOCM_DTR); + return _clear_lines(pComm, TIOCM_DTR); } static BOOL _set_rts(WINPR_COMM *pComm) { - SERIAL_HANDFLOW handflow; - if (!_get_handflow(pComm, &handflow)) - return FALSE; + // TMP: really required? + /* SERIAL_HANDFLOW handflow; */ + /* if (!_get_handflow(pComm, &handflow)) */ + /* return FALSE; */ - if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + /* if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) */ + /* { */ + /* SetLastError(ERROR_INVALID_PARAMETER); */ + /* return FALSE; */ + /* } */ - return _set_line(pComm, TIOCM_RTS); + return _set_lines(pComm, TIOCM_RTS); } static BOOL _clear_rts(WINPR_COMM *pComm) { - SERIAL_HANDFLOW handflow; - if (!_get_handflow(pComm, &handflow)) - return FALSE; + // TMP: really required? + /* SERIAL_HANDFLOW handflow; */ + /* if (!_get_handflow(pComm, &handflow)) */ + /* return FALSE; */ - if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + /* if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) */ + /* { */ + /* SetLastError(ERROR_INVALID_PARAMETER); */ + /* return FALSE; */ + /* } */ - return _clear_line(pComm, TIOCM_RTS); + return _clear_lines(pComm, TIOCM_RTS); } @@ -947,8 +964,13 @@ static BOOL _clear_rts(WINPR_COMM *pComm) static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) { UINT32 lines=0; - ioctl(pComm->fd, TIOCMGET, &lines); - + if (ioctl(pComm->fd, TIOCMGET, &lines) < 0) + { + DEBUG_WARN("TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + ZeroMemory(pRegister, sizeof(ULONG)); /* TODO: FIXME: how to get a direct access from the user space @@ -972,6 +994,257 @@ static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) return TRUE; } +/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ +static const ULONG _SERIAL_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) +{ + ULONG possibleMask; + + if (*pWaitMask == 0) + { + /* clearing pending events */ + + // TMP: TODO: + + if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0) + { + DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + pComm->pendingEvents = 0; + } + + // TMP: TODO: + // pending wait_on_mask must be stopped with STATUS_SUCCESS + // http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + + + possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK; + + if (possibleMask != *pWaitMask) + { + DEBUG_WARN("Not all wait events supported (Serial.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask); + + /* FIXME: shall we really set the possibleMask and return FALSE? */ + pComm->waitMask = possibleMask; + return FALSE; + } + + pComm->waitMask = possibleMask; + return TRUE; +} + + +static BOOL _get_wait_mask(WINPR_COMM *pComm, ULONG *pWaitMask) +{ + *pWaitMask = pComm->waitMask; + return TRUE; +} + + +static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) +{ + assert(*pOutputMask == 0); + + + /* TMP: TODO: while (TRUE) */ + { + int nbBytesToBeRead = 0; + int nbBytesToBeWritten = 0; + struct serial_icounter_struct currentCounters; + ULONG tiocmiwaitMask = 0; /* TIOCMIWAIT can wait for the 4 lines: TIOCM_RNG/DSR/CD/CTS */ + + if (ioctl(pComm->fd, TIOCINQ, &nbBytesToBeRead) < 0) + { + DEBUG_WARN("TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (ioctl(pComm->fd, TIOCOUTQ, &nbBytesToBeWritten) < 0) + { + DEBUG_WARN("TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); + if (ioctl(pComm->fd, TIOCGICOUNT, ¤tCounters) < 0) + { + DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* NB: preferred below "currentCounters.* != pComm->counters.*" over "currentCounters.* > pComm->counters.*" thinking the counters can loop */ + + + /* events */ + + if (pComm->waitMask & SERIAL_EV_RXCHAR) + { + if (nbBytesToBeRead > 0) + { + /* at least one character is pending to be read */ + *pOutputMask |= SERIAL_EV_RXCHAR; + } + } + + if (pComm->waitMask & SERIAL_EV_RXFLAG) + { + if (pComm->pendingEvents & SERIAL_EV_RXFLAG) // TMP: to be done in the ReadThread + { + /* the event character was received FIXME: is the character supposed to be still in the input buffer? */ + + /* event consumption */ + pComm->pendingEvents &= ~SERIAL_EV_RXFLAG; + *pOutputMask |= SERIAL_EV_RXFLAG; + } + } + + if (pComm->waitMask & SERIAL_EV_TXEMPTY) + { + if (nbBytesToBeWritten == 0) + { + /* NB: as of today CommWriteFile still blocks and uses the same thread than CommDeviceIoControl, + * it should be enough to just check nbBytesToBeWritten + */ + + /* the output buffer is empty */ + *pOutputMask |= SERIAL_EV_TXEMPTY; + } + } + + if (pComm->waitMask & SERIAL_EV_CTS) + { + tiocmiwaitMask |= TIOCM_CTS; + } + + if (pComm->waitMask & SERIAL_EV_DSR) + { + tiocmiwaitMask |= TIOCM_DSR; + } + + if (pComm->waitMask & SERIAL_EV_RLSD) + { + tiocmiwaitMask |= TIOCM_CD; + } + + if (pComm->waitMask & SERIAL_EV_BREAK) + { + if (currentCounters.brk != pComm->counters.brk) + { + *pOutputMask |= SERIAL_EV_BREAK; + + /* event consumption */ + pComm->counters.brk = currentCounters.brk; + } + } + + if (pComm->waitMask & SERIAL_EV_ERR) + { + if ((currentCounters.frame != pComm->counters.frame) || + (currentCounters.overrun != pComm->counters.overrun) || + (currentCounters.parity != pComm->counters.parity)) + { + *pOutputMask |= SERIAL_EV_ERR; + + /* event consumption */ + pComm->counters.frame = currentCounters.frame; + pComm->counters.overrun = currentCounters.overrun; + pComm->counters.parity = currentCounters.parity; + } + } + + if (pComm->waitMask & SERIAL_EV_RING) + { + tiocmiwaitMask |= TIOCM_RNG; + } + + if (pComm->waitMask & SERIAL_EV_RX80FULL) + { + if (nbBytesToBeRead > (0.8 * N_TTY_BUF_SIZE)) + *pOutputMask |= SERIAL_EV_RX80FULL; + } + + if ((*pOutputMask == 0) && /* don't need to wait more if at least an event already occured */ + (tiocmiwaitMask > 0)) + { + if ((pComm->waitMask & SERIAL_EV_CTS) && currentCounters.cts != pComm->counters.cts) + { + *pOutputMask |= SERIAL_EV_CTS; + + /* event consumption */ + pComm->counters.cts = currentCounters.cts; + } + + if ((pComm->waitMask & SERIAL_EV_DSR) && currentCounters.dsr != pComm->counters.dsr) + { + *pOutputMask |= SERIAL_EV_DSR; + + /* event consumption */ + pComm->counters.dsr = currentCounters.dsr; + } + + if ((pComm->waitMask & SERIAL_EV_RLSD) && currentCounters.dcd != pComm->counters.dcd) + { + *pOutputMask |= SERIAL_EV_RLSD; + + /* event consumption */ + pComm->counters.dcd = currentCounters.dcd; + } + + if ((pComm->waitMask & SERIAL_EV_RING) && currentCounters.rng != pComm->counters.rng) + { + *pOutputMask |= SERIAL_EV_RING; + + /* event consumption */ + pComm->counters.rng = currentCounters.rng; + } + + + /* FIXME: TIOCMIWAIT could be possible if _wait_on_mask gets its own thread */ + /* if (*pOutputMask == 0) */ + /* { */ + /* if (ioctl(pComm->fd, TIOCMIWAIT, &tiocmiwaitMask) < 0) */ + /* { */ + /* DEBUG_WARN("TIOCMIWAIT ioctl failed, errno=[%d] %s", errno, strerror(errno)); */ + /* SetLastError(ERROR_IO_DEVICE); */ + /* return FALSE; */ + /* } */ + /* /\* TODO: check counters again after TIOCMIWAIT *\/ */ + /* } */ + } + + if (*pOutputMask != 0) + { + /* at least an event occurred */ + return TRUE; + } + } + + DEBUG_WARN("_wait_on_mask pending on events:0X%0.4X", pComm->waitMask); + SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */ + return FALSE; +} + static REMOTE_SERIAL_DRIVER _SerialSys = { @@ -993,6 +1266,9 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_rts = _set_rts, .clear_rts = _clear_rts, .get_modemstatus = _get_modemstatus, + .set_wait_mask = _set_wait_mask, + .get_wait_mask = _get_wait_mask, + .wait_on_mask = _wait_on_mask, }; From 6cc44ff112262ada51e899afce8c04672f4eb3cd Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 14 May 2014 17:30:29 +0200 Subject: [PATCH 26/61] winpr-comm: got IOCTL_SERIAL_SET_QUEUE_SIZE --- channels/serial/client/serial_main.c | 2 +- winpr/include/winpr/comm.h | 4 +- winpr/libwinpr/comm/comm.c | 21 ++++++---- winpr/libwinpr/comm/comm_ioctl.c | 18 ++++++++ winpr/libwinpr/comm/comm_ioctl.h | 9 ++++ winpr/libwinpr/comm/comm_sercx2_sys.c | 3 ++ winpr/libwinpr/comm/comm_sercx_sys.c | 3 ++ winpr/libwinpr/comm/comm_serial_sys.c | 59 +++++++++++++++++++++------ 8 files changed, 95 insertions(+), 24 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 1b366c9d1..cf4c389f6 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -376,7 +376,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%x", IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); - // TMP: TODO: Status code to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests + // TMP: TODO: Status codes to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests switch(GetLastError()) { diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index ed79b4c0f..f11712c4d 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -421,7 +421,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD /* IOCTL_SERIAL_SET_XON 0x001B003C */ /* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ /* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ -/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */ +#define IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 #define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 #define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 #define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 @@ -481,7 +481,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = // {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"}, // {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"}, // {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"}, - // {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"}, + {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"}, {IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"}, {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, {IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"}, diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index f594fb377..7ddb26f92 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -679,18 +679,23 @@ BOOL PurgeComm(HANDLE hFile, DWORD dwFlags) BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { WINPR_COMM* pComm = (WINPR_COMM*) hFile; + SERIAL_QUEUE_SIZE queueSize; + DWORD bytesReturned = 0; - if (!pComm) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } -/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx */ -/* A process reinitializes a communications resource by using the SetupComm function, which performs the following tasks: */ + queueSize.InSize = dwInQueue; + queueSize.OutSize = dwOutQueue; -/* Terminates pending read and write operations, even if they have not been completed. */ -/* Discards unread characters and frees the internal output and input buffers of the driver associated with the specified resource. */ -/* Reallocates the internal output and input buffers. */ - -/* A process is not required to call SetupComm. If it does not, the resource's driver initializes the device with the default settings the first time that the communications resource handle is used. */ + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_QUEUE_SIZE, &queueSize, sizeof(SERIAL_QUEUE_SIZE), NULL, 0, &bytesReturned, NULL)) + { + DEBUG_WARN("SetCommTimeouts failure."); + return FALSE; + } return TRUE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 8583fa8d3..0966de66c 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -474,6 +474,24 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } + case IOCTL_SERIAL_SET_QUEUE_SIZE: + { + if (pRemoteSerialDriver->set_queue_size) + { + SERIAL_QUEUE_SIZE *pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_QUEUE_SIZE)); + if (nInBufferSize < sizeof(SERIAL_QUEUE_SIZE)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pRemoteSerialDriver->set_queue_size(pComm, pQueueSize); + } + break; + } + } DEBUG_WARN(_T("unsupported IoControlCode=[Ox%0.8x] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 3c582edde..65c82b752 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -161,6 +161,14 @@ typedef struct _SERIAL_TIMEOUTS #define SERIAL_EV_EVENT1 0x0800 #define SERIAL_EV_EVENT2 0x1000 + +typedef struct _SERIAL_QUEUE_SIZE +{ + ULONG InSize; + ULONG OutSize; +} SERIAL_QUEUE_SIZE, *PSERIAL_QUEUE_SIZE; + + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -189,6 +197,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 04e9960a3..10f732c5e 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -117,6 +117,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .set_wait_mask = _set_wait_mask, .get_wait_mask = NULL, .wait_on_mask = NULL, + .set_queue_size = NULL, }; @@ -155,6 +156,8 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask; _SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask; + _SerCx2Sys.set_queue_size = pSerialSys->set_queue_size; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index c00357eda..a275c0f58 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -554,6 +554,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .set_wait_mask = _set_wait_mask, .get_wait_mask = NULL, .wait_on_mask = NULL, + .set_queue_size = NULL, }; @@ -583,6 +584,8 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.get_wait_mask = pSerialSys->get_wait_mask; _SerCxSys.wait_on_mask = pSerialSys->wait_on_mask; + _SerCxSys.set_queue_size = pSerialSys->set_queue_size; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index ca004233f..7edec30fe 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -33,6 +33,13 @@ #include +/* hard-coded in N_TTY */ +#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ +#define TTY_THRESHOLD_UNTHROTTLE 128 +#define N_TTY_BUF_SIZE 4096 + + + /* * Linux, Windows speeds * @@ -150,7 +157,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363189%28v=vs.85%29.aspx */ - /* FIXME: properties should be better probe. The current + /* FIXME: properties should be better probed. The current * implementation just relies on the Linux' implementation. */ @@ -169,9 +176,9 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) /* pProperties->Reserved1; not used */ - // TMP: FIXME: related to the UART's FIFO ? - /* pProperties->MaxTxQueue; */ - /* pProperties->MaxRxQueue; */ + /* FIXME: could be implemented on top of N_TTY */ + pProperties->dwMaxTxQueue = N_TTY_BUF_SIZE; + pProperties->dwMaxRxQueue = N_TTY_BUF_SIZE; pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */ @@ -180,7 +187,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) /* TMP: TODO: to be finalized */ pProperties->dwProvCapabilities = - /*PCF_16BITMODE | PCF_DTRDSR | PCF_INTTIMEOUTS |*/ PCF_PARITY_CHECK | /*PCF_RLSD | */ + /*PCF_16BITMODE | PCF_DTRDSR |*/ PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD | */ PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS | PCF_TOTALTIMEOUTS |*/ PCF_XONXOFF; /* TMP: TODO: double check SP_RLSD */ @@ -196,9 +203,9 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->wSettableStopParity = STOPBITS_10 | /*STOPBITS_15 |*/ STOPBITS_20 | PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_MARK | PARITY_SPACE; - // TMP: FIXME: related to the UART's FIFO ? - /* pProperties->CurrentTxQueue; */ - /* pProperties->CurrentRxQueue; */ + /* FIXME: could be implemented on top of N_TTY */ + pProperties->dwCurrentTxQueue = N_TTY_BUF_SIZE; + pProperties->dwCurrentRxQueue = N_TTY_BUF_SIZE; /* pProperties->ProvSpec1; see above */ /* pProperties->ProvSpec2; ignored */ @@ -558,11 +565,6 @@ static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineContr } -/* hard-coded in N_TTY */ -#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ -#define TTY_THRESHOLD_UNTHROTTLE 128 -#define N_TTY_BUF_SIZE 4096 - static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) { BOOL result = TRUE; @@ -1246,6 +1248,36 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) } +static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSize) +{ + +/* TMP: FIXME: do at least a purge/reset ? */ +/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx */ +/* A process reinitializes a communications resource by using the SetupComm function, which performs the following tasks: */ + +/* Terminates pending read and write operations, even if they have not been completed. */ +/* Discards unread characters and frees the internal output and input buffers of the driver associated with the specified resource. */ +/* Reallocates the internal output and input buffers. */ + +/* A process is not required to call SetupComm. If it does not, the resource's driver initializes the device with the default settings the first time that the communications resource handle is used. */ + + + if ((pQueueSize->InSize <= N_TTY_BUF_SIZE) && (pQueueSize->OutSize <= N_TTY_BUF_SIZE)) + return TRUE; /* nothing to do */ + + /* FIXME: could be implemented on top of N_TTY */ + + if (pQueueSize->InSize > N_TTY_BUF_SIZE) + DEBUG_WARN("Requested an incompatible input buffer size: %d", pQueueSize->InSize); + + if (pQueueSize->OutSize > N_TTY_BUF_SIZE) + DEBUG_WARN("Requested an incompatible output buffer size: %d", pQueueSize->OutSize); + + SetLastError(ERROR_CANCELLED); + return FALSE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1269,6 +1301,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_wait_mask = _set_wait_mask, .get_wait_mask = _get_wait_mask, .wait_on_mask = _wait_on_mask, + .set_queue_size = _set_queue_size, }; From 8179affea97475475823ea5e0d947bfdefc6d69c Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 14 May 2014 21:21:31 +0200 Subject: [PATCH 27/61] winpr-comm: got IOCTL_SERIAL_PURGE --- channels/serial/client/serial_main.c | 16 +++++- winpr/include/winpr/comm.h | 9 ++- winpr/libwinpr/comm/comm.c | 21 ++++++- winpr/libwinpr/comm/comm.h | 5 ++ winpr/libwinpr/comm/comm_ioctl.c | 17 ++++++ winpr/libwinpr/comm/comm_ioctl.h | 9 ++- winpr/libwinpr/comm/comm_sercx2_sys.c | 28 ++++++++++ winpr/libwinpr/comm/comm_sercx_sys.c | 3 + winpr/libwinpr/comm/comm_serial_sys.c | 79 ++++++++++++++++++++++++++- 9 files changed, 177 insertions(+), 10 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index cf4c389f6..01a2af6d1 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -131,6 +131,9 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) goto error_handle; } + /* FIXME: this stinks, see also IOCTL_SERIAL_PURGE */ + _comm_set_ReadIrpQueue(serial->hComm, serial->ReadIrpQueue); + /* NOTE: binary mode/raw mode required for the redirection. On * Linux, CommCreateFileA forces this setting. */ @@ -246,7 +249,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) case ERROR_BAD_DEVICE: irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; break; - + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -404,10 +407,17 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_PENDING; break; + case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */ + irp->IoStatus = STATUS_INVALID_DEVICE_STATE; + break; + + case ERROR_CANCELLED: + irp->IoStatus = STATUS_CANCELLED; + break; + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); - //irp->IoStatus = STATUS_UNSUCCESSFUL; - irp->IoStatus = STATUS_CANCELLED; + irp->IoStatus = STATUS_UNSUCCESSFUL; break; } } diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index f11712c4d..3e362ab2b 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -21,10 +21,11 @@ #ifndef WINPR_COMM_H #define WINPR_COMM_H +#include +#include #include #include -#include #ifndef _WIN32 @@ -426,7 +427,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 #define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 /* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ -/* IOCTL_SERIAL_PURGE 0x001B004C */ +#define IOCTL_SERIAL_PURGE 0x001B004C #define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 #define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 #define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 @@ -486,7 +487,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, {IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"}, // {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, - // {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"}, + {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"}, {IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"}, {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, {IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"}, @@ -523,6 +524,8 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = */ const char* _comm_serial_ioctl_name(ULONG number); +void _comm_set_ReadIrpQueue(HANDLE hComm, wMessageQueue* ReadIrpQueue); + /** * FIXME: to be moved in comm_ioctl.h diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 7ddb26f92..91801571c 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -666,16 +666,28 @@ BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat) return TRUE; } + BOOL PurgeComm(HANDLE hFile, DWORD dwFlags) { WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned = 0; - if (!pComm) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_PURGE, &dwFlags, sizeof(DWORD), NULL, 0, &bytesReturned, NULL)) + { + DEBUG_WARN("PurgeComm failure."); + return FALSE; + } return TRUE; } + BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { WINPR_COMM* pComm = (WINPR_COMM*) hFile; @@ -1162,4 +1174,11 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare return INVALID_HANDLE_VALUE; } + +/* FIXME: to be removed */ +void _comm_set_ReadIrpQueue(HANDLE hComm, wMessageQueue* ReadIrpQueue) +{ + ((WINPR_COMM*)hComm)->ReadIrpQueue = ReadIrpQueue; +} + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 272eaa5bc..fcd8a8422 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -47,6 +47,11 @@ struct winpr_comm int fd; REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; + + wMessageQueue* ReadIrpQueue; /* considered as optional since it is + * defined outside of CommCreateFile + * FIXME: how to remove this shortcut? */ + COMMTIMEOUTS timeouts; struct serial_icounter_struct counters; diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 0966de66c..c3aab9a39 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -491,6 +491,23 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } break; } + case IOCTL_SERIAL_PURGE: + { + if (pRemoteSerialDriver->purge) + { + ULONG *pPurgeMask = (ULONG*)lpInBuffer; + + assert(nInBufferSize >= sizeof(ULONG)); + if (nInBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pRemoteSerialDriver->purge(pComm, pPurgeMask); + } + break; + } } diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 65c82b752..52fc35a9e 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -41,7 +41,8 @@ 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 @@ -169,6 +170,11 @@ typedef struct _SERIAL_QUEUE_SIZE } 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 + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -198,6 +204,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 10f732c5e..db03d3353 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -93,6 +93,32 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) } +static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) +{ + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */ + + if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT)) + { + DEBUG_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)) + { + DEBUG_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 REMOTE_SERIAL_DRIVER _SerCx2Sys = { @@ -118,6 +144,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_wait_mask = NULL, .wait_on_mask = NULL, .set_queue_size = NULL, + .purge = _purge, }; @@ -158,6 +185,7 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_queue_size = pSerialSys->set_queue_size; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index a275c0f58..04c6d55d2 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -555,6 +555,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_wait_mask = NULL, .wait_on_mask = NULL, .set_queue_size = NULL, + .purge = NULL, }; @@ -586,6 +587,8 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.set_queue_size = pSerialSys->set_queue_size; + _SerCxSys.purge = pSerialSys->purge; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 7edec30fe..68b309561 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -24,7 +24,9 @@ #include #include +#include #include +#include #include #include @@ -1065,8 +1067,8 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) { assert(*pOutputMask == 0); - - /* TMP: TODO: while (TRUE) */ + // TMP: TODO: + /* while (TRUE) */ { int nbBytesToBeRead = 0; int nbBytesToBeWritten = 0; @@ -1240,6 +1242,11 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) /* at least an event occurred */ return TRUE; } + + /* // TMP: */ + /* DEBUG_WARN("waiting on events:0X%0.4X", pComm->waitMask); */ + /* sleep(1); */ + } DEBUG_WARN("_wait_on_mask pending on events:0X%0.4X", pComm->waitMask); @@ -1278,6 +1285,73 @@ static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSi } +static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) +{ + if ((*pPurgeMask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR)) > 0) + { + DEBUG_WARN("Invalid purge mask: 0x%X\n", *pPurgeMask); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* FIXME: don't rely so much on how the IRP queues are implemented, should be more generic */ + + /* nothing to do until IRP_MJ_WRITE-s and IRP_MJ_DEVICE_CONTROL-s are executed in the same thread */ + /* if (*pPurgeMask & SERIAL_PURGE_TXABORT) */ + /* { */ + /* /\* Purges all write (IRP_MJ_WRITE) requests. *\/ */ + + /* } */ + + if (*pPurgeMask & SERIAL_PURGE_RXABORT) + { + /* Purges all read (IRP_MJ_READ) requests. */ + + if (pComm->ReadIrpQueue != NULL) + { + MessageQueue_Clear(pComm->ReadIrpQueue); + } + + /* TMP: TODO: double check if this gives well a change to abort a pending CommReadFile */ + fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) | O_NONBLOCK); + sleep(1); + fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK); + + /* TMP: FIXME: synchronization of the incoming + * IRP_MJ_READ-s. Could be possible to make them to + * transit first by the MainIrpQueue before to + * dispatch them */ + } + + if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) + { + /* Purges the transmit buffer, if one exists. */ + + if (tcflush(pComm->fd, TCOFLUSH) < 0) + { + DEBUG_WARN("tcflush(TCOFLUSH) failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_CANCELLED); + return FALSE; + } + } + + + if (*pPurgeMask & SERIAL_PURGE_RXCLEAR) + { + /* Purges the receive buffer, if one exists. */ + + if (tcflush(pComm->fd, TCIFLUSH) < 0) + { + DEBUG_WARN("tcflush(TCIFLUSH) failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_CANCELLED); + return FALSE; + } + } + + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1302,6 +1376,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_wait_mask = _get_wait_mask, .wait_on_mask = _wait_on_mask, .set_queue_size = _set_queue_size, + .purge = _purge, }; From baf4896a38bd5c67ccbf7832214586654efae85b Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 19 May 2014 16:53:57 +0200 Subject: [PATCH 28/61] serial: got rid of most the warning message with MAKE_BUILD_TYPE=Release winpr-comm: consolidated _set_handflow()/_get_handflow() winpr-comm: introduced a permissive mode winpr-comm: implementation of IOCTL_SERIAL_WAIT_ON_MASK still in progress --- channels/serial/client/serial_main.c | 25 ++- winpr/include/winpr/comm.h | 7 + winpr/libwinpr/comm/comm.c | 10 +- winpr/libwinpr/comm/comm.h | 13 +- winpr/libwinpr/comm/comm_io.c | 27 ++- winpr/libwinpr/comm/comm_ioctl.c | 80 +++++-- winpr/libwinpr/comm/comm_sercx2_sys.c | 2 +- winpr/libwinpr/comm/comm_sercx_sys.c | 302 ++++++-------------------- winpr/libwinpr/comm/comm_serial_sys.c | 183 ++++++++-------- 9 files changed, 293 insertions(+), 356 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 01a2af6d1..b0fa5d6f5 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -125,12 +125,18 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE)) { - DEBUG_WARN("CreateFile failure: %s last-error: Ox%x\n", serial->device.name, GetLastError()); + DEBUG_WARN("CreateFile failure: %s last-error: Ox%lX\n", serial->device.name, GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; goto error_handle; } + /* FIXME: Appeared to be useful to setup some devices. Guess + * the device driver asked to setup some unsupported feature + * that were not eventually used. TODO: collecting more + * details, a command line argument? */ + /* _comm_set_permissive(serial->hComm, TRUE); */ + /* FIXME: this stinks, see also IOCTL_SERIAL_PURGE */ _comm_set_ReadIrpQueue(serial->hComm, serial->ReadIrpQueue); @@ -208,7 +214,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) } - /* MSRDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored + /* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored * assert(Offset == 0); */ @@ -257,6 +263,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) } } + DEBUG_SVC("%lu bytes read from %s", nbRead, serial->device.name); error_handle: @@ -284,7 +291,12 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - assert(Offset == 0); /* not implemented otherwise */ + /* MS-RDPESP 3.2.5.1.5: The Offset field is ignored + * assert(Offset == 0); + * + * Using a serial printer, noticed though this field could be + * set. + */ DEBUG_SVC("writing %lu bytes to %s", Length, serial->device.name); @@ -296,7 +308,6 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) else { DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8x", serial->device.name, nbWritten, GetLastError()); - switch(GetLastError()) { case ERROR_INVALID_HANDLE: @@ -337,6 +348,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) irp->Complete(irp); } + static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) { UINT32 IoControlCode; @@ -367,7 +379,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_Read(irp->input, InputBuffer, InputBufferLength); - DEBUG_SVC("CommDeviceIoControl: IoControlCode=[0x%x] %s", IoControlCode, _comm_serial_ioctl_name(IoControlCode)); + DEBUG_SVC("CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%x] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) @@ -424,6 +436,8 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) error_handle: + assert(OutputBufferLength == BytesReturned); + Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */ if (BytesReturned > 0) @@ -541,6 +555,7 @@ static void* serial_thread_func(void* arg) return NULL; } + static void serial_irp_request(DEVICE* device, IRP* irp) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 3e362ab2b..f74dfd28b 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -524,6 +524,13 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = */ const char* _comm_serial_ioctl_name(ULONG number); +/** + * FIXME: got a proper function name and place + * + * permissive mode is disabled by default. + */ +BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive); + void _comm_set_ReadIrpQueue(HANDLE hComm, wMessageQueue* ReadIrpQueue); diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 91801571c..d0a7bedc0 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1029,7 +1029,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE)) { - DEBUG_WARN("unexpected access to the device: 0x%x", dwDesiredAccess); + DEBUG_WARN("unexpected access to the device: 0x%lX", dwDesiredAccess); } if (dwShareMode != 0) @@ -1043,7 +1043,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare if (lpSecurityAttributes != NULL) { - DEBUG_WARN("unexpected security attributes: 0x%x", lpSecurityAttributes); + DEBUG_WARN("unexpected security attributes, nLength=%lu", lpSecurityAttributes->nLength); } if (dwCreationDisposition != OPEN_EXISTING) @@ -1067,14 +1067,14 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare if (!S_ISCHR(deviceStat.st_mode)) { - DEBUG_WARN("bad device %d", devicePath); + DEBUG_WARN("bad device %s", devicePath); SetLastError(ERROR_BAD_DEVICE); return INVALID_HANDLE_VALUE; } if (dwFlagsAndAttributes != 0) { - DEBUG_WARN("unexpected flags and attributes: 0x%x", dwFlagsAndAttributes); + DEBUG_WARN("unexpected flags and attributes: 0x%lX", dwFlagsAndAttributes); } if (hTemplateFile != NULL) @@ -1146,7 +1146,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare /* upcomingTermios.c_cflag &= ~(CSIZE | PARENB); */ /* upcomingTermios.c_cflag |= CS8; */ - /* About missing missing flags recommended by termios(3) + /* About missing flags recommended by termios(3): * * IGNBRK and IXON, see: IOCTL_SERIAL_SET_HANDFLOW * CSIZE, PARENB and CS8, see: IOCTL_SERIAL_SET_LINE_CONTROL diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index fcd8a8422..3af153af9 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -46,6 +46,17 @@ struct winpr_comm WINPR_HANDLE_DEF(); int fd; + + /* permissive mode on errors if TRUE (default is FALSE). + * + * Since not all features are supported, some devices and applications + * can still be functional on such errors. + * + * TODO: command line switch or getting rid of it. + */ + BOOL permissive; + + REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; wMessageQueue* ReadIrpQueue; /* considered as optional since it is @@ -55,7 +66,7 @@ struct winpr_comm COMMTIMEOUTS timeouts; struct serial_icounter_struct counters; - ULONG waitMask; + ULONG waitMask; /* TMP: to be renamed EventMask */ ULONG pendingEvents; /* NB: CloseHandle() has to free resources */ diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index ed42fc50e..c6a08a3a5 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -34,6 +34,27 @@ #include "comm.h" +BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + pComm->permissive = permissive; + return TRUE; +} + + /* Computes Tmax in deciseconds (m and Tcare in milliseconds) */ static UCHAR _tmax(DWORD N, ULONG m, ULONG Tc) { @@ -200,10 +221,10 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (nbRead < 0) { - DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%d, ReadTotalTimeoutMultiplier=%d, ReadTotalTimeoutConstant=%d VMIN=%d, VTIME=%d", + DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u", pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); - DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%d, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); + DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); switch (errno) { @@ -287,7 +308,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite if (nbWritten < 0) { - DEBUG_WARN("CommWriteFile failed after %d bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); + DEBUG_WARN("CommWriteFile failed after %lu bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); switch (errno) { diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index c3aab9a39..1dd3e4bbe 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -72,22 +72,9 @@ const char* _comm_serial_ioctl_name(ULONG number) } -/** - * 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) +static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { - WINPR_COMM* pComm = (WINPR_COMM*) hDevice; REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; @@ -151,6 +138,17 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe switch (dwIoControlCode) { + case 0x220034: + case 0X1B006C: + DEBUG_WARN("Undocumented IoControlCode: 0X%X", dwIoControlCode); + *lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + if (pComm->permissive) + return FALSE; + else + return TRUE; + + break; case IOCTL_SERIAL_SET_BAUD_RATE: { if (pRemoteSerialDriver->set_baud_rate) @@ -467,7 +465,10 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } if (!pRemoteSerialDriver->wait_on_mask(pComm, pOutputMask)) + { + *lpBytesReturned = sizeof(ULONG); /* TMP: TODO: all lpBytesReturned values to be reviewed on error */ return FALSE; + } *lpBytesReturned = sizeof(ULONG); return TRUE; @@ -511,7 +512,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } - DEBUG_WARN(_T("unsupported IoControlCode=[Ox%0.8x] %s (remote serial driver: %s)"), + DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; @@ -519,6 +520,53 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } +/** + * 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; + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + result = _CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + + if (pComm->permissive) + { + if (!result) + { + DEBUG_WARN("[permissive]: whereas it failed, made to succeed IoControlCode=[0x%lX] %s, last-error: 0x%lX", + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError()); + } + + return TRUE; /* always! */ + } + + return result; +} + int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p) { int result; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index db03d3353..843ef4d20 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -81,7 +81,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) if (possibleMask != *pWaitMask) { - DEBUG_WARN("Not all wait events supported (SerCx2.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask); + DEBUG_WARN("Not all wait events supported (SerCx2.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ pComm->waitMask = possibleMask; diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 04c6d55d2..d01a3142f 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -180,7 +180,7 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) newSpeed = _SERCX_SYS_BAUD_TABLE[i][0]; if (cfsetspeed(&futureState, newSpeed) < 0) { - DEBUG_WARN("failed to set speed 0x%x (%d)", newSpeed, pBaudRate->BaudRate); + DEBUG_WARN("failed to set speed 0x%x (%lu)", newSpeed, pBaudRate->BaudRate); return FALSE; } @@ -188,7 +188,7 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%0.8x", GetLastError()); + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); return FALSE; } @@ -196,7 +196,7 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) } } - DEBUG_WARN("could not find a matching speed for the baud rate %d", pBaudRate->BaudRate); + DEBUG_WARN("could not find a matching speed for the baud rate %lu", pBaudRate->BaudRate); SetLastError(ERROR_INVALID_DATA); return FALSE; } @@ -231,264 +231,102 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) return FALSE; } -/* hard-coded in N_TTY */ -#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ -#define TTY_THRESHOLD_UNTHROTTLE 128 - -/* FIXME: mostly copied/pasted from comm_serial_sys.c, better share this code */ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) { + SERIAL_HANDFLOW SerCxHandflow; BOOL result = TRUE; - struct termios upcomingTermios; + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); - /* logical XOR */ - if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || - ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) - { - DEBUG_WARN("SERIAL_DTR_CONTROL cannot be different SERIAL_RTS_CONTROL, HUPCL will be set according SERIAL_RTS_CONTROL."); - result = FALSE; /* but keep on */ - } + memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW)); - ZeroMemory(&upcomingTermios, sizeof(struct termios)); - if (tcgetattr(pComm->fd, &upcomingTermios) < 0) - { - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } + /* filter out unsupported bits by SerCx.sys + * + * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx + */ - /* ControlHandShake */ + 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 (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) + if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake) { - upcomingTermios.c_cflag |= HUPCL; - } - else - { - upcomingTermios.c_cflag &= ~HUPCL; + if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) + { + DEBUG_WARN("SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys"); + } - /* FIXME: is the DTR line also needs to be forced to a disable state? */ - } + if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) + { + DEBUG_WARN("SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys"); + } - if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE) - { - /* DTR/DSR flow control not supported on Linux */ - DEBUG_WARN("Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature."); - SetLastError(ERROR_NOT_SUPPORTED); - result = FALSE; /* but keep on */ - } + if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) + { + DEBUG_WARN("SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys"); + } - if (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) - { - upcomingTermios.c_cflag |= CRTSCTS; - } - else - { - upcomingTermios.c_cflag &= ~CRTSCTS; - } - - if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE) - { - /* DTR/DSR flow control not supported on Linux */ - DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature."); - SetLastError(ERROR_NOT_SUPPORTED); - result = FALSE; /* but keep on */ - } - - /* SERIAL_DCD_HANDSHAKE unsupported by SerCx */ - if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) - { - DEBUG_WARN("Attempt to set SERIAL_DCD_HANDSHAKE (not implemented)"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ + result = FALSE; } - /* SERIAL_DSR_SENSITIVITY unsupported by SerCx */ - if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) + if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace) { - DEBUG_WARN("Attempt to set SERIAL_DSR_SENSITIVITY (not implemented)"); + if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT) + { + DEBUG_WARN("SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE) + { + DEBUG_WARN("SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR) + { + DEBUG_WARN("SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING) + { + DEBUG_WARN("SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR) + { + DEBUG_WARN("SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE) + { + DEBUG_WARN("SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys"); + } + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - /* SERIAL_ERROR_ABORT unsupported by SerCx */ - if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) - { - DEBUG_WARN("Attempt to set SERIAL_ERROR_ABORT (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - - /* FlowReplace */ - - /* SERIAL_AUTO_TRANSMIT unsupported by SerCx */ - if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT) - { - DEBUG_WARN("Attempt to set SERIAL_AUTO_TRANSMIT (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - - /* SERIAL_AUTO_RECEIVE unsupported by SerCx */ - if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE) - { - DEBUG_WARN("Attempt to set SERIAL_AUTO_RECEIVE (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - /* SERIAL_ERROR_CHAR unsupported by SerCx */ - if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR) - { - DEBUG_WARN("Attempt to set SERIAL_ERROR_CHAR (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - /* SERIAL_NULL_STRIPPING unsupported by SerCx */ - if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING) - { - DEBUG_WARN("Attempt to set SERIAL_NULL_STRIPPING (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - /* SERIAL_BREAK_CHAR unsupported by SerCx */ - if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR) - { - DEBUG_WARN("Attempt to set SERIAL_BREAK_CHAR (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - if (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) - { - upcomingTermios.c_cflag |= HUPCL; - } - else - { - upcomingTermios.c_cflag &= ~HUPCL; - - /* FIXME: is the RTS line also needs to be forced to a disable state? */ - } - - if (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) - { - upcomingTermios.c_cflag |= CRTSCTS; - } - else - { - upcomingTermios.c_cflag &= ~CRTSCTS; - } - - /* SERIAL_XOFF_CONTINUE unsupported by SerCx */ - if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE) - { - DEBUG_WARN("Attempt to set SERIAL_XOFF_CONTINUE (not implemented)"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - result = FALSE; /* but keep on */ - } - - - /* XonLimit */ - - // FIXME: could be implemented during read/write I/O - if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE) - { - DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %d", pHandflow->XonLimit); - SetLastError(ERROR_NOT_SUPPORTED); - result = FALSE; /* but keep on */ - } - - /* XoffChar */ - - // FIXME: could be implemented during read/write I/O - if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE) - { - DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %d", pHandflow->XoffLimit); - SetLastError(ERROR_NOT_SUPPORTED); - result = FALSE; /* but keep on */ + result = FALSE; } - - if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) - { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + if (!pSerialSys->set_handflow(pComm, &SerCxHandflow)) return FALSE; - } return result; } -/* FIXME: mostly copied/pasted from comm_serial_sys.c, better share this code */ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) { - struct termios currentTermios; + BOOL result; + REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); - ZeroMemory(¤tTermios, sizeof(struct termios)); - if (tcgetattr(pComm->fd, ¤tTermios) < 0) - { - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } + 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 + */ - /* ControlHandShake */ + 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); - pHandflow->ControlHandShake = 0; - - if (currentTermios.c_cflag & HUPCL) - pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL; - - /* SERIAL_DTR_HANDSHAKE unsupported */ - - if (currentTermios.c_cflag & CRTSCTS) - pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE; - - /* SERIAL_DSR_HANDSHAKE unsupported */ - - /* SERIAL_DCD_HANDSHAKE unsupported by SerCx */ - - /* SERIAL_DSR_SENSITIVITY unsupported by SerCx */ - - /* SERIAL_ERROR_ABORT unsupported by SerCx */ - - - /* FlowReplace */ - - pHandflow->FlowReplace = 0; - - /* SERIAL_AUTO_TRANSMIT unsupported by SerCx */ - - /* SERIAL_AUTO_RECEIVE unsupported by SerCx */ - - /* SERIAL_ERROR_CHAR unsupported by SerCx */ - - /* SERIAL_NULL_STRIPPING unsupported by SerCx */ - - /* SERIAL_BREAK_CHAR unsupported by SerCx */ - - if (currentTermios.c_cflag & HUPCL) - pHandflow->FlowReplace |= SERIAL_RTS_CONTROL; - - if (currentTermios.c_cflag & CRTSCTS) - pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE; - - /* SERIAL_XOFF_CONTINUE unsupported by SerCx */ - - - /* XonLimit */ - - pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE; - - - /* XoffLimit */ - - pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE; - - return TRUE; + return result; } @@ -518,7 +356,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) if (possibleMask != *pWaitMask) { - DEBUG_WARN("Not all wait events supported (SerCx.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask); + DEBUG_WARN("Not all wait events supported (SerCx.sys), requested events= 0x%lX, possible events= 0x%lX", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ pComm->waitMask = possibleMask; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 68b309561..ec3de5132 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -236,13 +236,13 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) newSpeed = _SERIAL_SYS_BAUD_TABLE[i][0]; if (cfsetspeed(&upcomingTermios, newSpeed) < 0) { - DEBUG_WARN("failed to set speed %d (%d)", newSpeed, pBaudRate->BaudRate); + DEBUG_WARN("failed to set speed %u (%lu)", newSpeed, pBaudRate->BaudRate); return FALSE; } if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); return FALSE; } @@ -250,7 +250,7 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) } } - DEBUG_WARN("could not find a matching speed for the baud rate %d", pBaudRate->BaudRate); + DEBUG_WARN("could not find a matching speed for the baud rate %lu", pBaudRate->BaudRate); SetLastError(ERROR_INVALID_DATA); return FALSE; } @@ -352,7 +352,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar result = FALSE; /* but keep on */ } - /* TMP: FIXME: Didn't find anything similar yet on Linux */ + /* TMP: FIXME: Didn't find anything similar yet on Linux. What about ISIG? */ if (pSerialChars->EventChar != '\0') { DEBUG_WARN("EventChar='%c' (0x%x) cannot be set\n", pSerialChars->EventChar, pSerialChars->EventChar); @@ -367,7 +367,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); return FALSE; } @@ -512,7 +512,7 @@ static BOOL _set_line_control(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLin if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); return FALSE; } @@ -572,15 +572,6 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) BOOL result = TRUE; struct termios upcomingTermios; - /* logical XOR */ - if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || - ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) - { - DEBUG_WARN("SERIAL_DTR_CONTROL cannot be different SERIAL_RTS_CONTROL, HUPCL will be set according SERIAL_RTS_CONTROL."); - result = FALSE; /* but keep on */ - } - - ZeroMemory(&upcomingTermios, sizeof(struct termios)); if (tcgetattr(pComm->fd, &upcomingTermios) < 0) { @@ -588,9 +579,18 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) return FALSE; } - /* ControlHandShake */ + /* HUPCL */ - if (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) + /* logical XOR */ + if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || + ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) + { + DEBUG_WARN("SERIAL_DTR_CONTROL:%s and SERIAL_RTS_CONTROL:%s cannot be different, HUPCL will be set since it is claimed for one of the both lines.", + (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) ? "ON" : "OFF", + (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) ? "ON" : "OFF"); + } + + if ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) || (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) { upcomingTermios.c_cflag |= HUPCL; } @@ -598,9 +598,34 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) { upcomingTermios.c_cflag &= ~HUPCL; - /* FIXME: is the DTR line also needs to be forced to a disable state? */ + /* FIXME: is the DTR line also needs to be forced to a disable state according SERIAL_DTR_CONTROL? */ + /* FIXME: is the RTS line also needs to be forced to a disable state according SERIAL_RTS_CONTROL? */ } + + /* CRTSCTS */ + + /* logical XOR */ + if ((!(pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) || + ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && !(pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE))) + { + DEBUG_WARN("SERIAL_CTS_HANDSHAKE:%s and SERIAL_RTS_HANDSHAKE:%s cannot be different, CRTSCTS will be set since it is claimed for one of the both lines.", + (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) ? "ON" : "OFF", + (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) ? "ON" : "OFF"); + } + + if ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) || (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) + { + upcomingTermios.c_cflag |= CRTSCTS; + } + else + { + upcomingTermios.c_cflag &= ~CRTSCTS; + } + + + /* ControlHandShake */ + if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE) { /* DTR/DSR flow control not supported on Linux */ @@ -610,15 +635,6 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) } - if (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) - { - upcomingTermios.c_cflag |= CRTSCTS; - } - else - { - upcomingTermios.c_cflag &= ~CRTSCTS; - } - if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE) { /* DTR/DSR flow control not supported on Linux */ @@ -673,12 +689,10 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) upcomingTermios.c_iflag &= ~IXOFF; } - // TMP: FIXME: could be implemented during read/write I/O + // TMP: FIXME: could be implemented during read/write I/O, as of today ErrorChar is necessary '\0' if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR) { - DEBUG_WARN("Attempt to use the unsupported SERIAL_ERROR_CHAR feature. A character with a parity error or framing error will be read as \0"); - - /* errors will be replaced by the character '\0' */ + /* errors will be replaced by the character '\0'. */ upcomingTermios.c_iflag &= ~IGNPAR; } else @@ -703,27 +717,6 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) result = FALSE; /* but keep on */ } - if (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) - { - upcomingTermios.c_cflag |= HUPCL; - } - else - { - upcomingTermios.c_cflag &= ~HUPCL; - - /* FIXME: is the RTS line also needs to be forced to a disable state? */ - } - - if (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) - { - upcomingTermios.c_cflag |= CRTSCTS; - } - else - { - upcomingTermios.c_cflag &= ~CRTSCTS; - } - - // FIXME: could be implemented during read/write I/O if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE) { @@ -738,7 +731,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) // FIXME: could be implemented during read/write I/O if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE) { - DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %d", pHandflow->XonLimit); + DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %lu", pHandflow->XonLimit); SetLastError(ERROR_NOT_SUPPORTED); result = FALSE; /* but keep on */ } @@ -748,7 +741,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) // FIXME: could be implemented during read/write I/O if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE) { - DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %d", pHandflow->XoffLimit); + DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %lu", pHandflow->XoffLimit); SetLastError(ERROR_NOT_SUPPORTED); result = FALSE; /* but keep on */ } @@ -756,7 +749,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { - DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError()); + DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); return FALSE; } @@ -873,7 +866,7 @@ static BOOL _set_lines(WINPR_COMM *pComm, UINT32 lines) { if (ioctl(pComm->fd, TIOCMBIS, &lines) < 0) { - DEBUG_WARN("TIOCMBIS ioctl failed, lines=0x%0.4X, errno=[%d] %s", lines, errno, strerror(errno)); + DEBUG_WARN("TIOCMBIS ioctl failed, lines=0x%X, errno=[%d] %s", lines, errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); return FALSE; } @@ -886,7 +879,7 @@ static BOOL _clear_lines(WINPR_COMM *pComm, UINT32 lines) { if (ioctl(pComm->fd, TIOCMBIC, &lines) < 0) { - DEBUG_WARN("TIOCMBIC ioctl failed, lines=0x%0.4X, errno=[%d] %s", lines, errno, strerror(errno)); + DEBUG_WARN("TIOCMBIC ioctl failed, lines=0x%X, errno=[%d] %s", lines, errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); return FALSE; } @@ -933,32 +926,30 @@ static BOOL _clear_dtr(WINPR_COMM *pComm) static BOOL _set_rts(WINPR_COMM *pComm) { - // TMP: really required? - /* SERIAL_HANDFLOW handflow; */ - /* if (!_get_handflow(pComm, &handflow)) */ - /* return FALSE; */ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; - /* if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) */ - /* { */ - /* SetLastError(ERROR_INVALID_PARAMETER); */ - /* return FALSE; */ - /* } */ + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } return _set_lines(pComm, TIOCM_RTS); } static BOOL _clear_rts(WINPR_COMM *pComm) { - // TMP: really required? - /* SERIAL_HANDFLOW handflow; */ - /* if (!_get_handflow(pComm, &handflow)) */ - /* return FALSE; */ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; - /* if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) */ - /* { */ - /* SetLastError(ERROR_INVALID_PARAMETER); */ - /* return FALSE; */ - /* } */ + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } return _clear_lines(pComm, TIOCM_RTS); } @@ -977,8 +968,9 @@ static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) ZeroMemory(pRegister, sizeof(ULONG)); - /* TODO: FIXME: how to get a direct access from the user space - * to the MSR register in order to complete the 4 first bits? + /* FIXME: Is the last read of the MSR register available or + * cached somewhere? Not quite sure we need to return the 4 + * LSBits anyway. */ /* #define SERIAL_MSR_DCTS 0x01 */ @@ -1038,13 +1030,13 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) // TMP: TODO: // pending wait_on_mask must be stopped with STATUS_SUCCESS // http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx - + // and pOutputMask = 0; possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK; if (possibleMask != *pWaitMask) { - DEBUG_WARN("Not all wait events supported (Serial.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask); + DEBUG_WARN("Not all wait events supported (Serial.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ pComm->waitMask = possibleMask; @@ -1067,7 +1059,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) { assert(*pOutputMask == 0); - // TMP: TODO: + // TMP: TODO: be sure to get a dedicated thread /* while (TRUE) */ { int nbBytesToBeRead = 0; @@ -1097,7 +1089,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) return FALSE; } - /* NB: preferred below "currentCounters.* != pComm->counters.*" over "currentCounters.* > pComm->counters.*" thinking the counters can loop */ + /* NB: preferred below (currentCounters.* != pComm->counters.*) over (currentCounters.* > pComm->counters.*) thinking the counters can loop */ /* events */ @@ -1224,8 +1216,9 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) } - /* FIXME: TIOCMIWAIT could be possible if _wait_on_mask gets its own thread */ - /* if (*pOutputMask == 0) */ + // TMP: TIOCMIWAIT could be possible if _wait_on_mask gets its own thread + /* if ((*pOutputMask == 0) && /\* don't bother at least one of the events event already occured *\/ */ + /* ((pComm->waitMask & ~(SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_RING)) == 0)) /\* only events handled by TIOCMIWAIT, otherwise go through the regular loop *\/ */ /* { */ /* if (ioctl(pComm->fd, TIOCMIWAIT, &tiocmiwaitMask) < 0) */ /* { */ @@ -1233,7 +1226,9 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) /* SetLastError(ERROR_IO_DEVICE); */ /* return FALSE; */ /* } */ - /* /\* TODO: check counters again after TIOCMIWAIT *\/ */ + + /* /\* check counters again after TIOCMIWAIT *\/ */ + /* continue; */ /* } */ } @@ -1243,13 +1238,14 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) return TRUE; } - /* // TMP: */ - /* DEBUG_WARN("waiting on events:0X%0.4X", pComm->waitMask); */ + /* /\* // TMP: *\/ */ + /* DEBUG_WARN("waiting on events:0X%lX", pComm->waitMask); */ + /* sleep(1); */ } - DEBUG_WARN("_wait_on_mask pending on events:0X%0.4X", pComm->waitMask); + DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->waitMask); SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */ return FALSE; } @@ -1275,10 +1271,10 @@ static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSi /* FIXME: could be implemented on top of N_TTY */ if (pQueueSize->InSize > N_TTY_BUF_SIZE) - DEBUG_WARN("Requested an incompatible input buffer size: %d", pQueueSize->InSize); + DEBUG_WARN("Requested an incompatible input buffer size: %lu", pQueueSize->InSize); if (pQueueSize->OutSize > N_TTY_BUF_SIZE) - DEBUG_WARN("Requested an incompatible output buffer size: %d", pQueueSize->OutSize); + DEBUG_WARN("Requested an incompatible output buffer size: %lu", pQueueSize->OutSize); SetLastError(ERROR_CANCELLED); return FALSE; @@ -1289,7 +1285,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { if ((*pPurgeMask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR)) > 0) { - DEBUG_WARN("Invalid purge mask: 0x%X\n", *pPurgeMask); + DEBUG_WARN("Invalid purge mask: 0x%lX\n", *pPurgeMask); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -1313,9 +1309,10 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) } /* TMP: TODO: double check if this gives well a change to abort a pending CommReadFile */ - fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) | O_NONBLOCK); - sleep(1); - fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK); + //assert(0); + /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) | O_NONBLOCK); */ + /* sleep(1); */ + /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK); */ /* TMP: FIXME: synchronization of the incoming * IRP_MJ_READ-s. Could be possible to make them to From 9639da0067889c8080d0ccbf1b308f19d24c4d0c Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 21 May 2014 10:36:55 +0200 Subject: [PATCH 29/61] serial: first steps to get a thread per IRP as a proof of concept. A bit of synchronization is still required. --- channels/serial/client/serial_main.c | 180 ++++++++++++++++++++------- winpr/libwinpr/comm/comm.h | 1 + 2 files changed, 133 insertions(+), 48 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index b0fa5d6f5..d4a9bc2d0 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -55,6 +55,8 @@ #include #include +#define MAX_IRP_THREADS 5 + typedef struct _SERIAL_DEVICE SERIAL_DEVICE; struct _SERIAL_DEVICE @@ -67,10 +69,19 @@ struct _SERIAL_DEVICE HANDLE MainThread; wMessageQueue* MainIrpQueue; - HANDLE ReadThread; - wMessageQueue* ReadIrpQueue; + /* one thread per pending IRP and indexed according their CompletionId */ + wListDictionary *IrpThreads; }; +typedef struct _IRP_THREAD_DATA IRP_THREAD_DATA; + +struct _IRP_THREAD_DATA +{ + SERIAL_DEVICE *serial; + IRP *irp; +}; + + static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { DWORD DesiredAccess; @@ -138,7 +149,8 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) /* _comm_set_permissive(serial->hComm, TRUE); */ /* FIXME: this stinks, see also IOCTL_SERIAL_PURGE */ - _comm_set_ReadIrpQueue(serial->hComm, serial->ReadIrpQueue); + // TMP: to be removed + //_comm_set_ReadIrpQueue(serial->hComm, serial->ReadIrpQueue); /* NOTE: binary mode/raw mode required for the redirection. On * Linux, CommCreateFileA forces this setting. @@ -498,36 +510,126 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) } } -static void* serial_read_thread_func(void* arg) +static void* irp_thread_func(void* arg) { - IRP* irp; - wMessage message; - SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; + IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg; - while (1) - { - if (!MessageQueue_Wait(serial->ReadIrpQueue)) - break; + /* blocks until the end of the request */ + serial_process_irp(data->serial, data->irp); - if (!MessageQueue_Peek(serial->ReadIrpQueue, &message, TRUE)) - break; - - if (message.id == WMQ_QUIT) - break; - - irp = (IRP*) message.wParam; - - if (irp) - { - assert(irp->MajorFunction == IRP_MJ_READ); - serial_process_irp(serial, irp); - } - } + free(data); ExitThread(0); return NULL; } + +static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) +{ + IRP_THREAD_DATA *data = NULL; + HANDLE irpThread = INVALID_HANDLE_VALUE; + HANDLE previousIrpThread; + + /* Checks whether a previous IRP with the same CompletionId + * was completed. NB: this can be the a recall of the same + * request let as blocking. Behavior at least observed with + * IOCTL_SERIAL_WAIT_ON_MASK. FIXME: to be confirmed. + */ + + // TMP: there is a slight chance that the server sends a new request with the same CompletionId whereas the previous thread is not yet terminated. + + previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)irp->CompletionId); + + if (previousIrpThread) + { + DWORD waitResult; + + /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */ + waitResult = WaitForSingleObject(previousIrpThread, 0); + + if (waitResult == WAIT_TIMEOUT) + { + /* Thread still alived */ + /* FIXME: how to send a kind of wake up signal to accelerate the pending request */ + + DEBUG_WARN("IRP with the CompletionId=%d not yet completed!", irp->CompletionId); + + // TMP: + assert(FALSE); /* assert() to be removed if it does realy happen */ + + /* FIXME: asserts that the previous thread's IRP is well the same request */ + irp->Discard(irp); + return; + } + else if(waitResult == WAIT_OBJECT_0) + { + DEBUG_SVC("previous IRP thread with CompletionId=%d naturally died", irp->CompletionId); + + /* the previous thread naturally died */ + CloseHandle(previousIrpThread); + ListDictionary_Remove(serial->IrpThreads, (void*)irp->CompletionId); + } + else + { + /* FIXME: handle more error cases */ + DEBUG_WARN("IRP CompletionId=%d : unexpected waitResult=%X"); + irp->Discard(irp); + + assert(FALSE); /* should not happen */ + + return; + } + } + + if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS) + { + DEBUG_WARN("Maximal number of IRP threads reached: %d", ListDictionary_Count(serial->IrpThreads)); + + assert(FALSE); + /* TODO: FIXME: WaitForMultipleObjects() not yet implemented for threads */ + } + + /* error_handle to be used ... */ + + data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA)); + if (data == NULL) + { + DEBUG_WARN("Could not allocate a new IRP_THREAD_DATA."); + goto error_handle; + } + + data->serial = serial; + data->irp = irp; + + irpThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE)irp_thread_func, + (void*)data, + 0, + NULL); + + if (irpThread == INVALID_HANDLE_VALUE) + { + DEBUG_WARN("Could not allocate a new IRP thread."); + goto error_handle; + } + + + + ListDictionary_Add(serial->IrpThreads, (void*)irp->CompletionId, irpThread); + + return; /* data freed by irp_thread_func */ + + error_handle: + + irp->IoStatus = STATUS_NO_MEMORY; + irp->Complete(irp); + + if (data) + free(data); +} + + static void* serial_thread_func(void* arg) { IRP* irp; @@ -548,7 +650,7 @@ static void* serial_thread_func(void* arg) irp = (IRP*) message.wParam; if (irp) - serial_process_irp(serial, irp); + create_irp_thread(serial, irp); } ExitThread(0); @@ -570,15 +672,7 @@ static void serial_irp_request(DEVICE* device, IRP* irp) * write requests. */ - switch(irp->MajorFunction) - { - case IRP_MJ_READ: - MessageQueue_Post(serial->ReadIrpQueue, NULL, 0, (void*) irp, NULL); - break; - - default: - MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); - } + MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); } static void serial_free(DEVICE* device) @@ -587,10 +681,6 @@ static void serial_free(DEVICE* device) WLog_Print(serial->log, WLOG_DEBUG, "freeing"); - MessageQueue_PostQuit(serial->ReadIrpQueue, 0); - WaitForSingleObject(serial->ReadThread, 100 /* ms */); /* INFINITE can block the process on a Read, FIXME: is a better signal possible? */ - CloseHandle(serial->ReadThread); - MessageQueue_PostQuit(serial->MainIrpQueue, 0); WaitForSingleObject(serial->MainThread, INFINITE); /* FIXME: might likely block on a pending Write or ioctl */ CloseHandle(serial->MainThread); @@ -600,8 +690,8 @@ static void serial_free(DEVICE* device) /* Clean up resources */ Stream_Free(serial->device.data, TRUE); - MessageQueue_Free(serial->ReadIrpQueue); MessageQueue_Free(serial->MainIrpQueue); + ListDictionary_Free(serial->IrpThreads); free(serial); } @@ -653,22 +743,16 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) for (i = 0; i <= len; i++) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); - serial->ReadIrpQueue = MessageQueue_New(NULL); serial->MainIrpQueue = MessageQueue_New(NULL); + serial->IrpThreads = ListDictionary_New(FALSE); /* only handled in create_irp_thread() */ + WLog_Init(); serial->log = WLog_Get("com.freerdp.channel.serial.client"); WLog_Print(serial->log, WLOG_DEBUG, "initializing"); pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); - serial->ReadThread = CreateThread(NULL, - 0, - (LPTHREAD_START_ROUTINE) serial_read_thread_func, - (void*) serial, - 0, - NULL); - serial->MainThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) serial_thread_func, diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 3af153af9..45999e332 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -57,6 +57,7 @@ struct winpr_comm BOOL permissive; + // TMP: to be renamed serverSerialDriverId REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; wMessageQueue* ReadIrpQueue; /* considered as optional since it is From ee268a92eee237fc9525316ccabb0f6506b2adb2 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 23 May 2014 12:27:09 +0200 Subject: [PATCH 30/61] serial: got a thread per IRP winpr-comm: got IOCTL_SERIAL_GET_COMMSTATUS, IOCTL_SERIAL_SET_BREAK_ON and IOCTL_SERIAL_SET_BREAK_OFF winpr-comm: tcdrain called by CommWriteFile() :( --- channels/serial/client/serial_main.c | 150 ++++++--- winpr/include/winpr/comm.h | 17 +- winpr/libwinpr/comm/comm.h | 8 +- winpr/libwinpr/comm/comm_io.c | 14 +- winpr/libwinpr/comm/comm_ioctl.c | 37 ++- winpr/libwinpr/comm/comm_ioctl.h | 27 ++ winpr/libwinpr/comm/comm_sercx2_sys.c | 7 + winpr/libwinpr/comm/comm_sercx_sys.c | 8 + winpr/libwinpr/comm/comm_serial_sys.c | 429 ++++++++++++++------------ 9 files changed, 436 insertions(+), 261 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index d4a9bc2d0..bc0154d72 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -71,6 +71,8 @@ struct _SERIAL_DEVICE /* one thread per pending IRP and indexed according their CompletionId */ wListDictionary *IrpThreads; + UINT32 IrpThreadToTerminateCount; + CRITICAL_SECTION TerminatingIrpThreadsLock; }; typedef struct _IRP_THREAD_DATA IRP_THREAD_DATA; @@ -180,8 +182,6 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) error_handle: Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ - - irp->Complete(irp); } static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) @@ -202,8 +202,6 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) error_handle: Stream_Zero(irp->output, 5); /* Padding (5 bytes) */ - - irp->Complete(irp); } static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) @@ -289,8 +287,6 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) if (buffer) free(buffer); - - irp->Complete(irp); } static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) @@ -357,7 +353,6 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - irp->Complete(irp); } @@ -391,11 +386,13 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_Read(irp->input, InputBuffer, InputBufferLength); - DEBUG_SVC("CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%x] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); + DEBUG_SVC("CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) { + /* DEBUG_SVC("CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s done", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); */ + irp->IoStatus = STATUS_SUCCESS; } else @@ -457,7 +454,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_EnsureRemainingCapacity(irp->output, BytesReturned); Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */ } - /* TMP: FIXME: Why at least Windows 2008R2 gets lost with this + /* FIXME: Why at least Windows 2008R2 gets lost with this * extra byte and likely on a IOCTL_SERIAL_SET_BAUD_RATE? The * extra byte is well required according MS-RDPEFS * 2.2.1.5.5 */ @@ -471,8 +468,6 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) if (OutputBuffer != NULL) free(OutputBuffer); - - irp->Complete(irp); } static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) @@ -505,11 +500,11 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) default: DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction); irp->IoStatus = STATUS_NOT_SUPPORTED; - irp->Complete(irp); break; } } + static void* irp_thread_func(void* arg) { IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg; @@ -517,6 +512,17 @@ static void* irp_thread_func(void* arg) /* blocks until the end of the request */ serial_process_irp(data->serial, data->irp); + EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock); + data->serial->IrpThreadToTerminateCount++; + + data->irp->Complete(data->irp); + + LeaveCriticalSection(&data->serial->TerminatingIrpThreadsLock); + + /* NB: At this point, the server might already being reusing + * the CompletionId whereas the thread is not yet + * terminated */ + free(data); ExitThread(0); @@ -530,56 +536,95 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) HANDLE irpThread = INVALID_HANDLE_VALUE; HANDLE previousIrpThread; - /* Checks whether a previous IRP with the same CompletionId - * was completed. NB: this can be the a recall of the same - * request let as blocking. Behavior at least observed with - * IOCTL_SERIAL_WAIT_ON_MASK. FIXME: to be confirmed. - */ + /* uncomment the code below to get a single thread per IRP for + * a test/debug purpose. NB: two IRPs could not occur at the + * same time, typically two concurent Read/Write + * operations. */ + /* serial_process_irp(serial, irp); */ + /* irp->Complete(irp); */ + /* return; */ - // TMP: there is a slight chance that the server sends a new request with the same CompletionId whereas the previous thread is not yet terminated. - previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)irp->CompletionId); - - if (previousIrpThread) + EnterCriticalSection(&serial->TerminatingIrpThreadsLock); + while (serial->IrpThreadToTerminateCount > 0) { - DWORD waitResult; + /* Cleaning up termitating and pending irp + * threads. See also: irp_thread_func() */ - /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */ - waitResult = WaitForSingleObject(previousIrpThread, 0); + HANDLE irpThread; + ULONG_PTR *ids; + int i, nbIds; - if (waitResult == WAIT_TIMEOUT) + nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids); + for (i=0; iCompletionId); + DWORD waitResult; + ULONG_PTR id = ids[i]; - // TMP: - assert(FALSE); /* assert() to be removed if it does realy happen */ - - /* FIXME: asserts that the previous thread's IRP is well the same request */ - irp->Discard(irp); - return; + irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id); + + /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */ + waitResult = WaitForSingleObject(irpThread, 0); + if (waitResult == WAIT_OBJECT_0) + { + /* terminating thread */ + + /* DEBUG_SVC("IRP thread with CompletionId=%d naturally died", id); */ + + CloseHandle(irpThread); + ListDictionary_Remove(serial->IrpThreads, (void*)id); + + serial->IrpThreadToTerminateCount--; + } + else if (waitResult != WAIT_TIMEOUT) + { + /* unexpected thread state */ + + DEBUG_WARN("WaitForSingleObject, got an unexpected result=0x%X\n", waitResult); + assert(FALSE); + } + /* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */ } - else if(waitResult == WAIT_OBJECT_0) + + + assert(serial->IrpThreadToTerminateCount == 0); /* TMP: */ + + if (serial->IrpThreadToTerminateCount > 0) { - DEBUG_SVC("previous IRP thread with CompletionId=%d naturally died", irp->CompletionId); - - /* the previous thread naturally died */ - CloseHandle(previousIrpThread); - ListDictionary_Remove(serial->IrpThreads, (void*)irp->CompletionId); - } - else - { - /* FIXME: handle more error cases */ - DEBUG_WARN("IRP CompletionId=%d : unexpected waitResult=%X"); - irp->Discard(irp); - - assert(FALSE); /* should not happen */ - - return; + DEBUG_SVC("%d IRP thread(s) not yet terminated", serial->IrpThreadToTerminateCount); + Sleep(1); /* 1 ms */ } } + LeaveCriticalSection(&serial->TerminatingIrpThreadsLock); + + /* NB: At this point and thanks to the synchronization we're + * sure that the incoming IRP uses well a recycled + * CompletionId or the server sent again an IRP already posted + * which didn't get yet a response (this later server behavior + * at least observed with IOCTL_SERIAL_WAIT_ON_MASK FIXME: + * behavior documented somewhere?). + */ + + previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)irp->CompletionId); + if (previousIrpThread) + { + /* Thread still alived <=> Request still pending */ + + DEBUG_SVC("IRP recall: IRP with the CompletionId=%d not yet completed!", irp->CompletionId); + + /* TMP: TODO: taking over the pending IRP or sending a kind of wake up signal to accelerate the pending request */ + assert(FALSE); + + /* FIXME: asserts that the previous thread's IRP is + * well the same request by checking more + * details. Need an access to the IRP object used by + * previousIrpThread */ + irp->Discard(irp); + return; + } + if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS) { @@ -589,6 +634,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) /* TODO: FIXME: WaitForMultipleObjects() not yet implemented for threads */ } + /* error_handle to be used ... */ data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA)); @@ -692,6 +738,7 @@ static void serial_free(DEVICE* device) Stream_Free(serial->device.data, TRUE); MessageQueue_Free(serial->MainIrpQueue); ListDictionary_Free(serial->IrpThreads); + DeleteCriticalSection(&serial->TerminatingIrpThreadsLock); free(serial); } @@ -747,6 +794,9 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->IrpThreads = ListDictionary_New(FALSE); /* only handled in create_irp_thread() */ + serial->IrpThreadToTerminateCount = 0; + InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); + WLog_Init(); serial->log = WLog_Get("com.freerdp.channel.serial.client"); WLog_Print(serial->log, WLOG_DEBUG, "initializing"); diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index f74dfd28b..9f3c34b7a 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -2,6 +2,8 @@ * WinPR: Windows Portable Runtime * Serial Communication API * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni * Copyright 2014 Marc-Andre Moreau * Copyright 2014 Hewlett-Packard Development Company, L.P. * @@ -420,8 +422,8 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_CLR_RTS 0x001B0034 /* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ /* IOCTL_SERIAL_SET_XON 0x001B003C */ -/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */ -/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */ +#define IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 +#define IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 #define IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 #define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 #define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 @@ -432,7 +434,10 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 #define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 /* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ -/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */ + +/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */ +#define IOCTL_SERIAL_GET_COMMSTATUS 0x001B006C + #define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 /* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ /* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ @@ -480,8 +485,8 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"}, // {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"}, // {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"}, - // {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"}, - // {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"}, + {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"}, + {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"}, {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"}, {IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"}, {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, @@ -492,7 +497,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, {IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"}, // {IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"}, - // {IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"}, + {IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"}, {IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"}, // {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"}, // {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"}, diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 45999e332..32ab91131 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -56,7 +56,6 @@ struct winpr_comm */ BOOL permissive; - // TMP: to be renamed serverSerialDriverId REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; @@ -66,9 +65,14 @@ struct winpr_comm COMMTIMEOUTS timeouts; + /* NB: no synchronization required on counters until _get_commstatus() + * is the only function [except CreateFile() and CloseHandle()] to + * modify counters */ struct serial_icounter_struct counters; + + /* TMP: TODO: sync */ ULONG waitMask; /* TMP: to be renamed EventMask */ - ULONG pendingEvents; + ULONG PendingEvents; /* NB: CloseHandle() has to free resources */ }; diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index c6a08a3a5..1d7ad919b 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -326,7 +326,19 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite *lpNumberOfBytesWritten += nbWritten; } - + + + /* 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 + * happenning otherwise. A purge was also done before each + * Write operation. The serial port was oppened with: + * DesiredAccess=0x0012019F. The printer worked fine with + * mstsc. */ + tcdrain(pComm->fd); + + return TRUE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 1dd3e4bbe..8c6ee43bc 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -139,7 +139,6 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l switch (dwIoControlCode) { case 0x220034: - case 0X1B006C: DEBUG_WARN("Undocumented IoControlCode: 0X%X", dwIoControlCode); *lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */ SetLastError(ERROR_CALL_NOT_IMPLEMENTED); @@ -509,7 +508,43 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } break; } + case IOCTL_SERIAL_GET_COMMSTATUS: + { + if (pRemoteSerialDriver->get_commstatus) + { + SERIAL_STATUS *pCommstatus = (SERIAL_STATUS*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_STATUS)); + if (nOutBufferSize < sizeof(SERIAL_STATUS)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + if (!pRemoteSerialDriver->get_commstatus(pComm, pCommstatus)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_STATUS); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_BREAK_ON: + { + if (pRemoteSerialDriver->set_break_on) + { + return pRemoteSerialDriver->set_break_on(pComm); + } + break; + } + case IOCTL_SERIAL_SET_BREAK_OFF: + { + if (pRemoteSerialDriver->set_break_off) + { + return pRemoteSerialDriver->set_break_off(pComm); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 52fc35a9e..bf337dcc3 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -175,6 +175,30 @@ typedef struct _SERIAL_QUEUE_SIZE #define SERIAL_PURGE_TXCLEAR 0x00000004 #define SERIAL_PURGE_RXCLEAR 0x00000008 +typedef struct _SERIAL_STATUS +{ + 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) + /** * A function might be NULL if not supported by the underlying remote driver. * @@ -205,6 +229,9 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 843ef4d20..15420cfde 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -145,6 +145,9 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .wait_on_mask = NULL, .set_queue_size = NULL, .purge = _purge, + .get_commstatus = NULL, + .set_break_on = NULL, + .set_break_off = NULL, }; @@ -185,6 +188,10 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _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; return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index d01a3142f..811b142f5 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -394,6 +394,9 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .wait_on_mask = NULL, .set_queue_size = NULL, .purge = NULL, + .get_commstatus = NULL, + .set_break_on = NULL, + .set_break_off = NULL, }; @@ -427,6 +430,11 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _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; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index ec3de5132..4f9cf16f1 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -967,10 +967,12 @@ static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) } ZeroMemory(pRegister, sizeof(ULONG)); - + /* FIXME: Is the last read of the MSR register available or * cached somewhere? Not quite sure we need to return the 4 - * LSBits anyway. + * LSBits anyway. A direct access to the register -- which + * would reset the register -- is likely not expected from + * this function. */ /* #define SERIAL_MSR_DCTS 0x01 */ @@ -1024,7 +1026,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) return FALSE; } - pComm->pendingEvents = 0; + pComm->PendingEvents = 0; } // TMP: TODO: @@ -1055,201 +1057,6 @@ static BOOL _get_wait_mask(WINPR_COMM *pComm, ULONG *pWaitMask) } -static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) -{ - assert(*pOutputMask == 0); - - // TMP: TODO: be sure to get a dedicated thread - /* while (TRUE) */ - { - int nbBytesToBeRead = 0; - int nbBytesToBeWritten = 0; - struct serial_icounter_struct currentCounters; - ULONG tiocmiwaitMask = 0; /* TIOCMIWAIT can wait for the 4 lines: TIOCM_RNG/DSR/CD/CTS */ - - if (ioctl(pComm->fd, TIOCINQ, &nbBytesToBeRead) < 0) - { - DEBUG_WARN("TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } - - if (ioctl(pComm->fd, TIOCOUTQ, &nbBytesToBeWritten) < 0) - { - DEBUG_WARN("TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } - - ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); - if (ioctl(pComm->fd, TIOCGICOUNT, ¤tCounters) < 0) - { - DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } - - /* NB: preferred below (currentCounters.* != pComm->counters.*) over (currentCounters.* > pComm->counters.*) thinking the counters can loop */ - - - /* events */ - - if (pComm->waitMask & SERIAL_EV_RXCHAR) - { - if (nbBytesToBeRead > 0) - { - /* at least one character is pending to be read */ - *pOutputMask |= SERIAL_EV_RXCHAR; - } - } - - if (pComm->waitMask & SERIAL_EV_RXFLAG) - { - if (pComm->pendingEvents & SERIAL_EV_RXFLAG) // TMP: to be done in the ReadThread - { - /* the event character was received FIXME: is the character supposed to be still in the input buffer? */ - - /* event consumption */ - pComm->pendingEvents &= ~SERIAL_EV_RXFLAG; - *pOutputMask |= SERIAL_EV_RXFLAG; - } - } - - if (pComm->waitMask & SERIAL_EV_TXEMPTY) - { - if (nbBytesToBeWritten == 0) - { - /* NB: as of today CommWriteFile still blocks and uses the same thread than CommDeviceIoControl, - * it should be enough to just check nbBytesToBeWritten - */ - - /* the output buffer is empty */ - *pOutputMask |= SERIAL_EV_TXEMPTY; - } - } - - if (pComm->waitMask & SERIAL_EV_CTS) - { - tiocmiwaitMask |= TIOCM_CTS; - } - - if (pComm->waitMask & SERIAL_EV_DSR) - { - tiocmiwaitMask |= TIOCM_DSR; - } - - if (pComm->waitMask & SERIAL_EV_RLSD) - { - tiocmiwaitMask |= TIOCM_CD; - } - - if (pComm->waitMask & SERIAL_EV_BREAK) - { - if (currentCounters.brk != pComm->counters.brk) - { - *pOutputMask |= SERIAL_EV_BREAK; - - /* event consumption */ - pComm->counters.brk = currentCounters.brk; - } - } - - if (pComm->waitMask & SERIAL_EV_ERR) - { - if ((currentCounters.frame != pComm->counters.frame) || - (currentCounters.overrun != pComm->counters.overrun) || - (currentCounters.parity != pComm->counters.parity)) - { - *pOutputMask |= SERIAL_EV_ERR; - - /* event consumption */ - pComm->counters.frame = currentCounters.frame; - pComm->counters.overrun = currentCounters.overrun; - pComm->counters.parity = currentCounters.parity; - } - } - - if (pComm->waitMask & SERIAL_EV_RING) - { - tiocmiwaitMask |= TIOCM_RNG; - } - - if (pComm->waitMask & SERIAL_EV_RX80FULL) - { - if (nbBytesToBeRead > (0.8 * N_TTY_BUF_SIZE)) - *pOutputMask |= SERIAL_EV_RX80FULL; - } - - if ((*pOutputMask == 0) && /* don't need to wait more if at least an event already occured */ - (tiocmiwaitMask > 0)) - { - if ((pComm->waitMask & SERIAL_EV_CTS) && currentCounters.cts != pComm->counters.cts) - { - *pOutputMask |= SERIAL_EV_CTS; - - /* event consumption */ - pComm->counters.cts = currentCounters.cts; - } - - if ((pComm->waitMask & SERIAL_EV_DSR) && currentCounters.dsr != pComm->counters.dsr) - { - *pOutputMask |= SERIAL_EV_DSR; - - /* event consumption */ - pComm->counters.dsr = currentCounters.dsr; - } - - if ((pComm->waitMask & SERIAL_EV_RLSD) && currentCounters.dcd != pComm->counters.dcd) - { - *pOutputMask |= SERIAL_EV_RLSD; - - /* event consumption */ - pComm->counters.dcd = currentCounters.dcd; - } - - if ((pComm->waitMask & SERIAL_EV_RING) && currentCounters.rng != pComm->counters.rng) - { - *pOutputMask |= SERIAL_EV_RING; - - /* event consumption */ - pComm->counters.rng = currentCounters.rng; - } - - - // TMP: TIOCMIWAIT could be possible if _wait_on_mask gets its own thread - /* if ((*pOutputMask == 0) && /\* don't bother at least one of the events event already occured *\/ */ - /* ((pComm->waitMask & ~(SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_RING)) == 0)) /\* only events handled by TIOCMIWAIT, otherwise go through the regular loop *\/ */ - /* { */ - /* if (ioctl(pComm->fd, TIOCMIWAIT, &tiocmiwaitMask) < 0) */ - /* { */ - /* DEBUG_WARN("TIOCMIWAIT ioctl failed, errno=[%d] %s", errno, strerror(errno)); */ - /* SetLastError(ERROR_IO_DEVICE); */ - /* return FALSE; */ - /* } */ - - /* /\* check counters again after TIOCMIWAIT *\/ */ - /* continue; */ - /* } */ - } - - if (*pOutputMask != 0) - { - /* at least an event occurred */ - return TRUE; - } - - /* /\* // TMP: *\/ */ - /* DEBUG_WARN("waiting on events:0X%lX", pComm->waitMask); */ - - /* sleep(1); */ - - } - - DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->waitMask); - SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */ - return FALSE; -} - static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSize) { @@ -1289,7 +1096,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - + /* FIXME: don't rely so much on how the IRP queues are implemented, should be more generic */ /* nothing to do until IRP_MJ_WRITE-s and IRP_MJ_DEVICE_CONTROL-s are executed in the same thread */ @@ -1303,15 +1110,16 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { /* Purges all read (IRP_MJ_READ) requests. */ + // TMP: if (pComm->ReadIrpQueue != NULL) { + assert(0); MessageQueue_Clear(pComm->ReadIrpQueue); } /* TMP: TODO: double check if this gives well a change to abort a pending CommReadFile */ - //assert(0); + /* assert(0); */ /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) | O_NONBLOCK); */ - /* sleep(1); */ /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK); */ /* TMP: FIXME: synchronization of the incoming @@ -1348,6 +1156,222 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) return TRUE; } +/* NB: _get_commstatus also produces most of the events consumed by _wait_on_mask(). Exceptions: + * - SERIAL_EV_RXFLAG: FIXME: once EventChar supported + * + */ +static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) +{ + /* http://msdn.microsoft.com/en-us/library/jj673022%28v=vs.85%29.aspx */ + + struct serial_icounter_struct currentCounters; + + ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS)); + + ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); + if (ioctl(pComm->fd, TIOCGICOUNT, ¤tCounters) < 0) + { + DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* NB: preferred below (currentCounters.* != pComm->counters.*) over (currentCounters.* > pComm->counters.*) thinking the counters can loop */ + + /* Errors */ + + if (currentCounters.buf_overrun != pComm->counters.buf_overrun) + { + pCommstatus->Errors |= SERIAL_ERROR_QUEUEOVERRUN; + } + + if (currentCounters.overrun != pComm->counters.overrun) + { + pCommstatus->Errors |= SERIAL_ERROR_OVERRUN; + pComm->PendingEvents |= SERIAL_EV_ERR; + } + + if (currentCounters.brk != pComm->counters.brk) + { + pCommstatus->Errors |= SERIAL_ERROR_BREAK; + pComm->PendingEvents |= SERIAL_EV_BREAK; + } + + if (currentCounters.parity != pComm->counters.parity) + { + pCommstatus->Errors |= SERIAL_ERROR_PARITY; + pComm->PendingEvents |= SERIAL_EV_ERR; + } + + if (currentCounters.frame != pComm->counters.frame) + { + pCommstatus->Errors |= SERIAL_ERROR_FRAMING; + pComm->PendingEvents |= SERIAL_EV_ERR; + } + + + /* HoldReasons TMP: TODO: see also _set_lines(), _clear_lines() the LCR register. */ + + /* AmountInInQueue */ + + if (ioctl(pComm->fd, TIOCINQ, &(pCommstatus->AmountInInQueue)) < 0) + { + DEBUG_WARN("TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + + /* AmountInOutQueue */ + + if (ioctl(pComm->fd, TIOCOUTQ, &(pCommstatus->AmountInOutQueue)) < 0) + { + DEBUG_WARN("TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* BOOLEAN EofReceived; FIXME: once EofChar supported */ + + + /* BOOLEAN WaitForImmediate; TMP: TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR supported */ + + + /* other events based on counters */ + + if (currentCounters.rx != pComm->counters.rx) + { + pComm->PendingEvents |= SERIAL_EV_RXCHAR; + } + + if ((currentCounters.tx != pComm->counters.tx) && /* at least a transmission occurred AND ...*/ + (pCommstatus->AmountInOutQueue == 0)) /* output bufer is now empty */ + { + pComm->PendingEvents |= SERIAL_EV_TXEMPTY; + } + else + { + /* FIXME: "now empty" is ambiguous, need to track previous completed transmission? */ + pComm->PendingEvents &= ~SERIAL_EV_TXEMPTY; + } + + if (currentCounters.cts != pComm->counters.cts) + { + pComm->PendingEvents |= SERIAL_EV_CTS; + } + + if (currentCounters.dsr != pComm->counters.dsr) + { + pComm->PendingEvents |= SERIAL_EV_DSR; + } + + if (currentCounters.dcd != pComm->counters.dcd) + { + pComm->PendingEvents |= SERIAL_EV_RLSD; + } + + if (currentCounters.rng != pComm->counters.rng) + { + pComm->PendingEvents |= SERIAL_EV_RING; + } + + if (pCommstatus->AmountInInQueue > (0.8 * N_TTY_BUF_SIZE)) + { + pComm->PendingEvents |= SERIAL_EV_RX80FULL; + } + else + { + /* FIXME: "is 80 percent full" is ambiguous, need to track when it previously occured? */ + pComm->PendingEvents &= ~SERIAL_EV_RX80FULL; + } + + + pComm->counters = currentCounters; + + + return TRUE; +} + +static void _consume_event(WINPR_COMM *pComm, ULONG *pOutputMask, ULONG event) +{ + if ((pComm->waitMask & event) && (pComm->PendingEvents & event)) + { + pComm->PendingEvents &= ~event; /* consumed */ + *pOutputMask |= event; + } +} + +static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) +{ + assert(*pOutputMask == 0); + + + while (TRUE) + { + SERIAL_STATUS serialStatus; + + /* NB: also ensures PendingEvents to be up to date */ + ZeroMemory(&serialStatus, sizeof(SERIAL_STATUS)); + if (!_get_commstatus(pComm, &serialStatus)) + { + return FALSE; + } + + /* events */ + + _consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR); + _consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG); + _consume_event(pComm, pOutputMask, SERIAL_EV_TXEMPTY); + _consume_event(pComm, pOutputMask, SERIAL_EV_CTS); + _consume_event(pComm, pOutputMask, SERIAL_EV_DSR); + _consume_event(pComm, pOutputMask, SERIAL_EV_RLSD); + _consume_event(pComm, pOutputMask, SERIAL_EV_BREAK); + _consume_event(pComm, pOutputMask, SERIAL_EV_ERR); + _consume_event(pComm, pOutputMask, SERIAL_EV_RING ); + _consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL); + + if (*pOutputMask != 0) + { + /* at least an event occurred */ + return TRUE; + } + + /* // TMP: */ + DEBUG_WARN("waiting on events:0X%lX", pComm->waitMask); + + sleep(1); // TMP: TODO: wait also on a PendingEvents modification, and a new identical IRP + } + + DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->waitMask); + SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */ + return FALSE; +} + +static BOOL _set_break_on(WINPR_COMM *pComm) +{ + if (ioctl(pComm->fd, TIOCSBRK, NULL) < 0) + { + DEBUG_WARN("TIOCSBRK ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _set_break_off(WINPR_COMM *pComm) +{ + if (ioctl(pComm->fd, TIOCCBRK, NULL) < 0) + { + DEBUG_WARN("TIOCSBRK ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + static REMOTE_SERIAL_DRIVER _SerialSys = { @@ -1374,6 +1398,9 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .wait_on_mask = _wait_on_mask, .set_queue_size = _set_queue_size, .purge = _purge, + .get_commstatus = _get_commstatus, + .set_break_on = _set_break_on, + .set_break_off = _set_break_off, }; From 4feafcc40db3d83d5915ee9d7e62b3cc0c3f35fc Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 23 May 2014 13:04:43 +0200 Subject: [PATCH 31/61] winpr-comm: got IOCTL_SERIAL_SET_XOFF and IOCTL_SERIAL_SET_XON --- winpr/include/winpr/comm.h | 8 ++++---- winpr/libwinpr/comm/comm_ioctl.c | 16 +++++++++++++++ winpr/libwinpr/comm/comm_ioctl.h | 2 ++ winpr/libwinpr/comm/comm_sercx2_sys.c | 5 +++++ winpr/libwinpr/comm/comm_sercx_sys.c | 6 ++++++ winpr/libwinpr/comm/comm_serial_sys.c | 28 +++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 9f3c34b7a..095cd64d9 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -420,8 +420,8 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD /* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ #define IOCTL_SERIAL_SET_RTS 0x001B0030 #define IOCTL_SERIAL_CLR_RTS 0x001B0034 -/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */ -/* IOCTL_SERIAL_SET_XON 0x001B003C */ +#define IOCTL_SERIAL_SET_XOFF 0x001B0038 +#define IOCTL_SERIAL_SET_XON 0x001B003C #define IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 #define IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 #define IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 @@ -483,8 +483,8 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = // {IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"}, {IOCTL_SERIAL_SET_RTS, "IOCTL_SERIAL_SET_RTS"}, {IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"}, - // {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"}, - // {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"}, + {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"}, + {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"}, {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"}, {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"}, {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"}, diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 8c6ee43bc..e6d52cf9c 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -545,6 +545,22 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } break; } + case IOCTL_SERIAL_SET_XOFF: + { + if (pRemoteSerialDriver->set_xoff) + { + return pRemoteSerialDriver->set_xoff(pComm); + } + break; + } + case IOCTL_SERIAL_SET_XON: + { + if (pRemoteSerialDriver->set_xon) + { + return pRemoteSerialDriver->set_xon(pComm); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index bf337dcc3..107fe2cd4 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -232,6 +232,8 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 15420cfde..ba0275200 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -148,6 +148,8 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_commstatus = NULL, .set_break_on = NULL, .set_break_off = NULL, + .set_xoff = NULL, + .set_xon = NULL, }; @@ -193,6 +195,9 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_break_on = pSerialSys->set_break_on; _SerCx2Sys.set_break_off = pSerialSys->set_break_off; + _SerCx2Sys.set_xoff = pSerialSys->set_xoff; + _SerCx2Sys.set_xon = pSerialSys->set_xon; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 811b142f5..1a9671d28 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -397,6 +397,8 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_commstatus = NULL, .set_break_on = NULL, .set_break_off = NULL, + .set_xoff = NULL, + .set_xon = NULL, }; @@ -435,6 +437,10 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _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; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 4f9cf16f1..5cb773b5b 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1373,6 +1373,32 @@ static BOOL _set_break_off(WINPR_COMM *pComm) } +static BOOL _set_xoff(WINPR_COMM *pComm) +{ + if (tcflow(pComm->fd, TCIOFF) < 0) + { + DEBUG_WARN("TCIOFF failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _set_xon(WINPR_COMM *pComm) +{ + if (tcflow(pComm->fd, TCION) < 0) + { + DEBUG_WARN("TCION failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1401,6 +1427,8 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_commstatus = _get_commstatus, .set_break_on = _set_break_on, .set_break_off = _set_break_off, + .set_xoff = _set_xoff, + .set_xon = _set_xon, }; From 1cb1fd67643e12995364b689adaab97fc4fabe34 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 23 May 2014 15:06:15 +0200 Subject: [PATCH 32/61] winpr-comm: IOCTL_SERIAL_SET_XON / IOCTL_SERIAL_SET_XOFF not supposed to be supported by SerCx2.sys --- winpr/libwinpr/comm/comm_sercx2_sys.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index ba0275200..0a01189e7 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -148,8 +148,8 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_commstatus = NULL, .set_break_on = NULL, .set_break_off = NULL, - .set_xoff = NULL, - .set_xon = NULL, + .set_xoff = NULL, /* not supported by SerCx2.sys */ + .set_xon = NULL, /* not supported by SerCx2.sys */ }; @@ -195,9 +195,6 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_break_on = pSerialSys->set_break_on; _SerCx2Sys.set_break_off = pSerialSys->set_break_off; - _SerCx2Sys.set_xoff = pSerialSys->set_xoff; - _SerCx2Sys.set_xon = pSerialSys->set_xon; - return &_SerCx2Sys; } From a36467c353a2f3a32e880b646c57028928abb5eb Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 23 May 2014 15:16:07 +0200 Subject: [PATCH 33/61] winpr-comm: don't loop yet on IOCTL_SERIAL_WAIT_ON_MASK --- winpr/libwinpr/comm/comm_serial_sys.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 5cb773b5b..3d9a5a9b3 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1305,8 +1305,9 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) { assert(*pOutputMask == 0); - - while (TRUE) + // TMP: TODO: + // TMP: TODO: wait also on a PendingEvents modification, and a new identical IRP + /* while (TRUE) */ { SERIAL_STATUS serialStatus; @@ -1335,11 +1336,6 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) /* at least an event occurred */ return TRUE; } - - /* // TMP: */ - DEBUG_WARN("waiting on events:0X%lX", pComm->waitMask); - - sleep(1); // TMP: TODO: wait also on a PendingEvents modification, and a new identical IRP } DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->waitMask); From 5dc21b56043920619322c342d7ad63093d0ce349 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 23 May 2014 15:55:44 +0200 Subject: [PATCH 34/61] winpr-comm: renamed waitMask WaitEventMask winpr-comm: removed ReadIrpQueue --- channels/serial/client/serial_main.c | 4 ---- winpr/include/winpr/comm.h | 2 -- winpr/libwinpr/comm/comm.c | 6 ----- winpr/libwinpr/comm/comm.h | 6 +---- winpr/libwinpr/comm/comm_sercx2_sys.c | 2 +- winpr/libwinpr/comm/comm_sercx_sys.c | 2 +- winpr/libwinpr/comm/comm_serial_sys.c | 34 +++++++++------------------ 7 files changed, 14 insertions(+), 42 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index bc0154d72..b45ff2f2e 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -150,10 +150,6 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) * details, a command line argument? */ /* _comm_set_permissive(serial->hComm, TRUE); */ - /* FIXME: this stinks, see also IOCTL_SERIAL_PURGE */ - // TMP: to be removed - //_comm_set_ReadIrpQueue(serial->hComm, serial->ReadIrpQueue); - /* NOTE: binary mode/raw mode required for the redirection. On * Linux, CommCreateFileA forces this setting. */ diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 095cd64d9..fe9313f10 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -536,8 +536,6 @@ const char* _comm_serial_ioctl_name(ULONG number); */ BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive); -void _comm_set_ReadIrpQueue(HANDLE hComm, wMessageQueue* ReadIrpQueue); - /** * FIXME: to be moved in comm_ioctl.h diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index d0a7bedc0..11d8d10f4 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1175,10 +1175,4 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } -/* FIXME: to be removed */ -void _comm_set_ReadIrpQueue(HANDLE hComm, wMessageQueue* ReadIrpQueue) -{ - ((WINPR_COMM*)hComm)->ReadIrpQueue = ReadIrpQueue; -} - #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 32ab91131..e9bc1678a 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -59,10 +59,6 @@ struct winpr_comm // TMP: to be renamed serverSerialDriverId REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; - wMessageQueue* ReadIrpQueue; /* considered as optional since it is - * defined outside of CommCreateFile - * FIXME: how to remove this shortcut? */ - COMMTIMEOUTS timeouts; /* NB: no synchronization required on counters until _get_commstatus() @@ -71,7 +67,7 @@ struct winpr_comm struct serial_icounter_struct counters; /* TMP: TODO: sync */ - ULONG waitMask; /* TMP: to be renamed EventMask */ + ULONG WaitEventMask; ULONG PendingEvents; /* NB: CloseHandle() has to free resources */ diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 0a01189e7..e2915dd64 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -84,7 +84,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) DEBUG_WARN("Not all wait events supported (SerCx2.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ - pComm->waitMask = possibleMask; + pComm->WaitEventMask = possibleMask; return FALSE; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 1a9671d28..87b1d1dbe 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -359,7 +359,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) DEBUG_WARN("Not all wait events supported (SerCx.sys), requested events= 0x%lX, possible events= 0x%lX", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ - pComm->waitMask = possibleMask; + pComm->WaitEventMask = possibleMask; return FALSE; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 3d9a5a9b3..8fc9ea8d2 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1041,18 +1041,18 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) DEBUG_WARN("Not all wait events supported (Serial.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ - pComm->waitMask = possibleMask; + pComm->WaitEventMask = possibleMask; return FALSE; } - pComm->waitMask = possibleMask; + pComm->WaitEventMask = possibleMask; return TRUE; } static BOOL _get_wait_mask(WINPR_COMM *pComm, ULONG *pWaitMask) { - *pWaitMask = pComm->waitMask; + *pWaitMask = pComm->WaitEventMask; return TRUE; } @@ -1097,35 +1097,23 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) return FALSE; } - /* FIXME: don't rely so much on how the IRP queues are implemented, should be more generic */ - /* nothing to do until IRP_MJ_WRITE-s and IRP_MJ_DEVICE_CONTROL-s are executed in the same thread */ - /* if (*pPurgeMask & SERIAL_PURGE_TXABORT) */ - /* { */ - /* /\* Purges all write (IRP_MJ_WRITE) requests. *\/ */ + if (*pPurgeMask & SERIAL_PURGE_TXABORT) + { + /* Purges all write (IRP_MJ_WRITE) requests. */ - /* } */ + + // TMP: TODO: intercept this call before CommDeviceIoControl() ? + } if (*pPurgeMask & SERIAL_PURGE_RXABORT) { /* Purges all read (IRP_MJ_READ) requests. */ - // TMP: - if (pComm->ReadIrpQueue != NULL) - { - assert(0); - MessageQueue_Clear(pComm->ReadIrpQueue); - } - /* TMP: TODO: double check if this gives well a change to abort a pending CommReadFile */ /* assert(0); */ /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) | O_NONBLOCK); */ /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK); */ - - /* TMP: FIXME: synchronization of the incoming - * IRP_MJ_READ-s. Could be possible to make them to - * transit first by the MainIrpQueue before to - * dispatch them */ } if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) @@ -1294,7 +1282,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) static void _consume_event(WINPR_COMM *pComm, ULONG *pOutputMask, ULONG event) { - if ((pComm->waitMask & event) && (pComm->PendingEvents & event)) + if ((pComm->WaitEventMask & event) && (pComm->PendingEvents & event)) { pComm->PendingEvents &= ~event; /* consumed */ *pOutputMask |= event; @@ -1338,7 +1326,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) } } - DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->waitMask); + DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->WaitEventMask); SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */ return FALSE; } From 1b54ecfc00eb089762602f1536934d802b9786d1 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 23 May 2014 17:46:05 +0200 Subject: [PATCH 35/61] winpr-comm: replaced the cumbersome hashtable for defined COM defines by a simpler array[128] --- winpr/libwinpr/comm/comm.c | 104 ++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 11d8d10f4..5d34fb3d1 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -39,7 +39,6 @@ #include #include -#include #include #include "comm_ioctl.h" @@ -745,40 +744,19 @@ BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) /* Extended API */ -/* FIXME: DefineCommDevice / QueryCommDevice look over complicated for - * just a couple of strings, should be simplified. - * - * TODO: what about libwinpr-io.so? - */ -static wHashTable *_CommDevices = NULL; +typedef struct _COMM_DEVICE +{ + LPTSTR name; + LPTSTR path; +} COMM_DEVICE; + +/* FIXME: get a clever data structure */ +static COMM_DEVICE **_CommDevices = NULL; + +#define COMM_DEVICE_MAX 128 static HANDLE_CREATOR *_CommHandleCreator = NULL; -static int deviceNameCmp(void* pointer1, void* pointer2) -{ - return _tcscmp(pointer1, pointer2); -} - - -static int devicePathCmp(void* pointer1, void* pointer2) -{ - return _tcscmp(pointer1, pointer2); -} - -/* copied from HashTable.c */ -static unsigned long HashTable_StringHashFunctionA(void* key) -{ - int c; - unsigned long hash = 5381; - unsigned char* str = (unsigned char*) key; - - /* djb2 algorithm */ - while ((c = *str++) != '\0') - hash = (hash * 33) + c; - - return hash; -} - static void _CommDevicesInit() { @@ -790,12 +768,7 @@ static void _CommDevicesInit() if (_CommDevices == NULL) { - _CommDevices = HashTable_New(TRUE); - _CommDevices->keycmp = deviceNameCmp; - _CommDevices->valuecmp = devicePathCmp; - _CommDevices->hashFunction = HashTable_StringHashFunctionA; /* TMP: FIXME: need of a HashTable_StringHashFunctionW */ - _CommDevices->keyDeallocator = free; - _CommDevices->valueDeallocator = free; + _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); _CommHandleCreator = (HANDLE_CREATOR*)malloc(sizeof(HANDLE_CREATOR)); _CommHandleCreator->IsHandled = IsCommDevice; @@ -852,6 +825,7 @@ static BOOL _IsReservedCommDeviceName(LPCTSTR lpName) */ BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath) { + int i = 0; LPTSTR storedDeviceName = NULL; LPTSTR storedTargetPath = NULL; @@ -885,9 +859,40 @@ BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTarget goto error_handle; } - if (HashTable_Add(_CommDevices, storedDeviceName, storedTargetPath) < 0) + for (i=0; iname, storedDeviceName) == 0) + { + /* take over the emplacement */ + free(_CommDevices[i]->name); + free(_CommDevices[i]->path); + _CommDevices[i]->name = storedDeviceName; + _CommDevices[i]->path = storedTargetPath; + + break; + } + } + else + { + /* new emplacement */ + _CommDevices[i] = (COMM_DEVICE*)calloc(1, sizeof(COMM_DEVICE)); + if (_CommDevices[i] == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + _CommDevices[i]->name = storedDeviceName; + _CommDevices[i]->path = storedTargetPath; + break; + } + } + + if (i == COMM_DEVICE_MAX) + { + SetLastError(ERROR_OUTOFMEMORY); goto error_handle; } @@ -922,6 +927,7 @@ BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTarget */ DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) { + int i; LPTSTR storedTargetPath; SetLastError(ERROR_SUCCESS); @@ -939,7 +945,23 @@ DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) return 0; } - storedTargetPath = HashTable_GetItemValue(_CommDevices, (void*)lpDeviceName); + storedTargetPath = NULL; + for (i=0; iname, lpDeviceName) == 0) + { + storedTargetPath = _CommDevices[i]->path; + break; + } + + continue; + } + + break; + } + if (storedTargetPath == NULL) { SetLastError(ERROR_INVALID_DATA); From 13e10c5de9d256f8da159b2a5981a732076c2b8c Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 26 May 2014 16:31:56 +0200 Subject: [PATCH 36/61] winpr-comm: identified the ioctl 0x00220034 as IOCTL_USBPRINT_GET_1284_ID (support not yet implemented) --- winpr/include/winpr/comm.h | 7 ++++++- winpr/libwinpr/comm/comm.c | 2 +- winpr/libwinpr/comm/comm.h | 2 +- winpr/libwinpr/comm/comm_ioctl.c | 13 +++++-------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index fe9313f10..290f7367d 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -461,6 +461,9 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD /* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ /* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ +/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */ +#define IOCTL_USBPRINT_GET_1284_ID 0x220034 + typedef struct __SERIAL_IOCTL_NAME { @@ -503,7 +506,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = // {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"}, // {IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"}, // {IOCTL_SERIAL_GET_STATS, "IOCTL_SERIAL_GET_STATS"}, - // {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"}; + // {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"}, // {IOCTL_SERIAL_GET_MODEM_CONTROL,"IOCTL_SERIAL_GET_MODEM_CONTROL"}, // {IOCTL_SERIAL_SET_MODEM_CONTROL,"IOCTL_SERIAL_SET_MODEM_CONTROL"}, // {IOCTL_SERIAL_SET_FIFO_CONTROL, "IOCTL_SERIAL_SET_FIFO_CONTROL"}, @@ -521,6 +524,8 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = // {IOCTL_PAR_QUERY_RAW_DEVICE_ID, "IOCTL_PAR_QUERY_RAW_DEVICE_ID"}, // {IOCTL_PAR_IS_PORT_FREE, "IOCTL_PAR_IS_PORT_FREE"}, + {IOCTL_USBPRINT_GET_1284_ID, "IOCTL_USBPRINT_GET_1284_ID"}, + {0, NULL} }; diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 5d34fb3d1..a32f4cd7a 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -5,7 +5,7 @@ * Copyright 2011 O.S. Systems Software Ltda. * Copyright 2011 Eduardo Fiss Beloni * Copyright 2014 Marc-Andre Moreau - * Copyright 2014 Hewlett-Packard Development Company, L.P. + * 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. diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index e9bc1678a..cbd4b15f0 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -3,7 +3,7 @@ * Serial Communication API * * Copyright 2014 Marc-Andre Moreau - * Copyright 2014 Hewlett-Packard Development Company, L.P. + * 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. diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index e6d52cf9c..b9cddefa3 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -138,16 +138,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l switch (dwIoControlCode) { - case 0x220034: - DEBUG_WARN("Undocumented IoControlCode: 0X%X", 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); - if (pComm->permissive) - return FALSE; - else - return TRUE; - - break; + return FALSE; + } case IOCTL_SERIAL_SET_BAUD_RATE: { if (pRemoteSerialDriver->set_baud_rate) From 979622493646be48d53d220baedd504647cf0541 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 27 May 2014 11:33:10 +0200 Subject: [PATCH 37/61] - winpr-comm: got a finalized version of IOCTL_SERIAL_WAIT_ON_MASK - serial: cleaning up the code --- channels/serial/client/serial_main.c | 85 +++++++++++++------- winpr/include/winpr/comm.h | 2 +- winpr/libwinpr/comm/comm.c | 13 ++- winpr/libwinpr/comm/comm.h | 7 +- winpr/libwinpr/comm/comm_ioctl.h | 1 - winpr/libwinpr/comm/comm_serial_sys.c | 110 ++++++++++++++++++++++---- winpr/libwinpr/handle/handle.c | 11 +++ 7 files changed, 175 insertions(+), 54 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index b45ff2f2e..4294ab33b 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -64,14 +64,16 @@ struct _SERIAL_DEVICE DEVICE device; HANDLE* hComm; - // TMP: use of log + /* TODO: use of log (prefered the old fashion DEBUG_SVC and + * DEBUG_WARN macros for backward compatibility resaons) + */ wLog* log; HANDLE MainThread; wMessageQueue* MainIrpQueue; /* one thread per pending IRP and indexed according their CompletionId */ wListDictionary *IrpThreads; - UINT32 IrpThreadToTerminateCount; + UINT32 IrpThreadToBeTerminatedCount; CRITICAL_SECTION TerminatingIrpThreadsLock; }; @@ -509,7 +511,7 @@ static void* irp_thread_func(void* arg) serial_process_irp(data->serial, data->irp); EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock); - data->serial->IrpThreadToTerminateCount++; + data->serial->IrpThreadToBeTerminatedCount++; data->irp->Complete(data->irp); @@ -532,17 +534,21 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) HANDLE irpThread = INVALID_HANDLE_VALUE; HANDLE previousIrpThread; - /* uncomment the code below to get a single thread per IRP for - * a test/debug purpose. NB: two IRPs could not occur at the - * same time, typically two concurent Read/Write - * operations. */ + /* for a test/debug purpose, uncomment the code below to get a + * single thread for all IRPs. NB: two IRPs could not be + * processed at the same time, typically two concurent + * Read/Write operations could block each other. */ /* serial_process_irp(serial, irp); */ /* irp->Complete(irp); */ /* return; */ + /* NOTE: for good or bad, this implementation relies on the + * server to avoid a flooding of requests. see also _purge(). + */ + EnterCriticalSection(&serial->TerminatingIrpThreadsLock); - while (serial->IrpThreadToTerminateCount > 0) + while (serial->IrpThreadToBeTerminatedCount > 0) { /* Cleaning up termitating and pending irp * threads. See also: irp_thread_func() */ @@ -572,7 +578,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) CloseHandle(irpThread); ListDictionary_Remove(serial->IrpThreads, (void*)id); - serial->IrpThreadToTerminateCount--; + serial->IrpThreadToBeTerminatedCount--; } else if (waitResult != WAIT_TIMEOUT) { @@ -585,11 +591,9 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) } - assert(serial->IrpThreadToTerminateCount == 0); /* TMP: */ - - if (serial->IrpThreadToTerminateCount > 0) + if (serial->IrpThreadToBeTerminatedCount > 0) { - DEBUG_SVC("%d IRP thread(s) not yet terminated", serial->IrpThreadToTerminateCount); + DEBUG_SVC("%d IRP thread(s) not yet terminated", serial->IrpThreadToBeTerminatedCount); Sleep(1); /* 1 ms */ } } @@ -599,8 +603,11 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) * sure that the incoming IRP uses well a recycled * CompletionId or the server sent again an IRP already posted * which didn't get yet a response (this later server behavior - * at least observed with IOCTL_SERIAL_WAIT_ON_MASK FIXME: - * behavior documented somewhere?). + * at least observed with IOCTL_SERIAL_WAIT_ON_MASK and + * mstsc.exe. + * + * FIXME: behavior documented somewhere? behavior not yet + * observed with FreeRDP). */ previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)irp->CompletionId); @@ -610,13 +617,24 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) DEBUG_SVC("IRP recall: IRP with the CompletionId=%d not yet completed!", irp->CompletionId); - /* TMP: TODO: taking over the pending IRP or sending a kind of wake up signal to accelerate the pending request */ - assert(FALSE); - - /* FIXME: asserts that the previous thread's IRP is - * well the same request by checking more - * details. Need an access to the IRP object used by - * previousIrpThread */ + assert(FALSE); /* unimplemented */ + + /* TODO: asserts that previousIrpThread handles well + * the same request by checking more details. Need an + * access to the IRP object used by previousIrpThread + */ + + /* TODO: taking over the pending IRP or sending a kind + * of wake up signal to accelerate the pending + * request + * + * To be considered: + * if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) { + * pComm->PendingEvents |= SERIAL_EV_FREERDP_*; + * sem_post(&comm->PendingEventsSem); + * } + */ + irp->Discard(irp); return; } @@ -624,10 +642,15 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS) { - DEBUG_WARN("Maximal number of IRP threads reached: %d", ListDictionary_Count(serial->IrpThreads)); + DEBUG_WARN("Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads)); - assert(FALSE); - /* TODO: FIXME: WaitForMultipleObjects() not yet implemented for threads */ + assert(FALSE); /* unimplemented */ + + /* TODO: MAX_IRP_THREADS has been thought to avoid a + * flooding of pending requests. Use + * WaitForMultipleObjects() when available in winpr + * for threads. + */ } @@ -643,6 +666,8 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) data->serial = serial; data->irp = irp; + /* data freed by irp_thread_func */ + irpThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)irp_thread_func, @@ -660,7 +685,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) ListDictionary_Add(serial->IrpThreads, (void*)irp->CompletionId, irpThread); - return; /* data freed by irp_thread_func */ + return; error_handle: @@ -757,7 +782,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if (!name || (name[0] == '*')) { - /* TODO: implement auto detection of parallel ports */ + /* TODO: implement auto detection of serial ports */ return 0; } @@ -788,9 +813,9 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->MainIrpQueue = MessageQueue_New(NULL); - serial->IrpThreads = ListDictionary_New(FALSE); /* only handled in create_irp_thread() */ - - serial->IrpThreadToTerminateCount = 0; + /* IrpThreads content only modified by create_irp_thread() */ + serial->IrpThreads = ListDictionary_New(FALSE); + serial->IrpThreadToBeTerminatedCount = 0; InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); WLog_Init(); diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 290f7367d..c7bc8babc 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -388,7 +388,7 @@ WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOver * * Did something close to QueryDosDevice() and DefineDosDevice() but with * folowing constraints: - * - mappings are stored in a static wHashTable (thread safe) + * - mappings are stored in a static array. * - QueryCommDevice returns only the mappings that have been defined through DefineCommDevice() */ WINPR_API BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath); diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index a32f4cd7a..36b2a53e5 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -750,7 +750,7 @@ typedef struct _COMM_DEVICE LPTSTR path; } COMM_DEVICE; -/* FIXME: get a clever data structure */ +/* FIXME: get a clever data structure, see also io.h functions */ static COMM_DEVICE **_CommDevices = NULL; #define COMM_DEVICE_MAX 128 @@ -809,7 +809,7 @@ static BOOL _IsReservedCommDeviceName(LPCTSTR lpName) return TRUE; } - /* TMP: TODO: PRN ? */ + /* FIXME: what about PRN ? */ return FALSE; } @@ -1147,9 +1147,14 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } + if (sem_init(&pComm->PendingEventsSem, 0, 0) < 0) + { + DEBUG_WARN("sem_init failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } - - + InitializeCriticalSection(&pComm->PendingEventsLock); /* The binary/raw mode is required for the redirection but * only flags that are not handle somewhere-else, except diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index cbd4b15f0..14e862235 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -24,6 +24,7 @@ #ifndef _WIN32 #include +#include #include @@ -66,9 +67,10 @@ struct winpr_comm * modify counters */ struct serial_icounter_struct counters; - /* TMP: TODO: sync */ ULONG WaitEventMask; ULONG PendingEvents; + sem_t PendingEventsSem; + CRITICAL_SECTION PendingEventsLock; /* NB: CloseHandle() has to free resources */ }; @@ -77,6 +79,9 @@ typedef struct winpr_comm WINPR_COMM; void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); +/* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 107fe2cd4..cf3f642c0 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -162,7 +162,6 @@ typedef struct _SERIAL_TIMEOUTS #define SERIAL_EV_EVENT1 0x0800 #define SERIAL_EV_EVENT2 0x1000 - typedef struct _SERIAL_QUEUE_SIZE { ULONG InSize; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 8fc9ea8d2..ea87e353c 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -26,8 +26,9 @@ #include #include #include -#include #include +#include +#include #include @@ -1028,11 +1029,16 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) pComm->PendingEvents = 0; } + + /* Stops pending IOCTL_SERIAL_WAIT_ON_MASK + * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + */ + EnterCriticalSection(&pComm->PendingEventsLock); + pComm->PendingEvents |= SERIAL_EV_FREERDP_STOP; + sem_post(&pComm->PendingEventsSem); + LeaveCriticalSection(&pComm->PendingEventsLock); + - // TMP: TODO: - // pending wait_on_mask must be stopped with STATUS_SUCCESS - // http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx - // and pOutputMask = 0; possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK; @@ -1104,6 +1110,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) // TMP: TODO: intercept this call before CommDeviceIoControl() ? + // getting a fd_write, fd_read and fs_iotcl? } if (*pPurgeMask & SERIAL_PURGE_RXABORT) @@ -1154,6 +1161,8 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) struct serial_icounter_struct currentCounters; + EnterCriticalSection(&pComm->PendingEventsLock); + ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS)); ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); @@ -1239,7 +1248,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) } else { - /* FIXME: "now empty" is ambiguous, need to track previous completed transmission? */ + /* FIXME: "now empty" from the specs is ambiguous, need to track previous completed transmission? */ pComm->PendingEvents &= ~SERIAL_EV_TXEMPTY; } @@ -1269,17 +1278,33 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) } else { - /* FIXME: "is 80 percent full" is ambiguous, need to track when it previously occured? */ + /* FIXME: "is 80 percent full" from the specs is ambiguous, need to track when it previously occured? */ pComm->PendingEvents &= ~SERIAL_EV_RX80FULL; } pComm->counters = currentCounters; + LeaveCriticalSection(&pComm->PendingEventsLock); return TRUE; } +static BOOL _refresh_PendingEvents(WINPR_COMM *pComm) +{ + SERIAL_STATUS serialStatus; + + /* NB: also ensures PendingEvents to be up to date */ + ZeroMemory(&serialStatus, sizeof(SERIAL_STATUS)); + if (!_get_commstatus(pComm, &serialStatus)) + { + return FALSE; + } + + return TRUE; +} + + static void _consume_event(WINPR_COMM *pComm, ULONG *pOutputMask, ULONG event) { if ((pComm->WaitEventMask & event) && (pComm->PendingEvents & event)) @@ -1289,25 +1314,31 @@ static void _consume_event(WINPR_COMM *pComm, ULONG *pOutputMask, ULONG event) } } +/* + * NB: see also: _set_wait_mask() + */ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) { + assert(*pOutputMask == 0); - // TMP: TODO: - // TMP: TODO: wait also on a PendingEvents modification, and a new identical IRP - /* while (TRUE) */ - { - SERIAL_STATUS serialStatus; + /* UGLY: removes the STOP bit set by an initial _set_wait_mask() */ + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; - /* NB: also ensures PendingEvents to be up to date */ - ZeroMemory(&serialStatus, sizeof(SERIAL_STATUS)); - if (!_get_commstatus(pComm, &serialStatus)) + while (TRUE) + { + struct timespec ts; + + if (!_refresh_PendingEvents(pComm)) { return FALSE; } + /* events */ + EnterCriticalSection(&pComm->PendingEventsLock); + _consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR); _consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG); _consume_event(pComm, pOutputMask, SERIAL_EV_TXEMPTY); @@ -1319,15 +1350,60 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) _consume_event(pComm, pOutputMask, SERIAL_EV_RING ); _consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL); + LeaveCriticalSection(&pComm->PendingEventsLock); + + /* NOTE: PendingEvents can be modified from now on but + * not pOutputMask */ + if (*pOutputMask != 0) { /* at least an event occurred */ return TRUE; } + + + /* wait for 1 ms or a modification of PendingEvents */ + + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) + { + DEBUG_WARN("clock_realtime failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + ts.tv_nsec += 100000000; /* 100 ms */ + if (ts.tv_nsec > 999999999) + { + ts.tv_sec++; /* += 1s */ + ts.tv_nsec -= 1000000000; /* -= 1s */ + } + if (sem_timedwait(&pComm->PendingEventsSem, &ts) < 0) + { + assert(errno == ETIMEDOUT); + + if (errno != ETIMEDOUT) + { + DEBUG_WARN("sem_timedwait failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + } + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) + { + EnterCriticalSection(&pComm->PendingEventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; + LeaveCriticalSection(&pComm->PendingEventsLock); + + /* pOutputMask must remain empty + * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + */ + return TRUE; + } } - DEBUG_WARN("_wait_on_mask pending on events:0X%lX", pComm->WaitEventMask); - SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */ + DEBUG_WARN("_wait_on_mask, unexpected return, WaitEventMask=0X%lX", pComm->WaitEventMask); + assert(FALSE); return FALSE; } diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 855b7db59..5a40d632a 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -206,6 +206,17 @@ BOOL CloseHandle(HANDLE hObject) if (comm->fd > 0) close(comm->fd); + /* NOTE: avoided to add a dependency by using a + * function such as _stop_wait_on_mask() */ + EnterCriticalSection(&comm->PendingEventsLock); + comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; + sem_post(&comm->PendingEventsSem); + LeaveCriticalSection(&comm->PendingEventsLock); + + sem_destroy(&comm->PendingEventsSem); /* FIXME: might be too early? */ + + DeleteCriticalSection(&comm->PendingEventsLock); + free(comm); return TRUE; From b889ad712546735ef71e3880bd14e1c619b1cc0d Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 27 May 2014 12:29:24 +0200 Subject: [PATCH 38/61] winpr-comm: reviewed the synchronization around counters, WaitMask and PendingEvents variables. Got rid of the semaphore PendingEventsSem. --- channels/serial/client/serial_main.c | 1 - winpr/libwinpr/comm/comm.c | 11 +-- winpr/libwinpr/comm/comm.h | 8 +-- winpr/libwinpr/comm/comm_serial_sys.c | 97 ++++++++++++--------------- winpr/libwinpr/handle/handle.c | 17 +++-- 5 files changed, 54 insertions(+), 80 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 4294ab33b..0a9348857 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -631,7 +631,6 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) * To be considered: * if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) { * pComm->PendingEvents |= SERIAL_EV_FREERDP_*; - * sem_post(&comm->PendingEventsSem); * } */ diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 36b2a53e5..742eac397 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1139,6 +1139,8 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare */ pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; + InitializeCriticalSection(&pComm->EventsLock); + if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0) { DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); @@ -1147,15 +1149,6 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } - if (sem_init(&pComm->PendingEventsSem, 0, 0) < 0) - { - DEBUG_WARN("sem_init failed, errno=[%d] %s", errno, strerror(errno)); - SetLastError(ERROR_IO_DEVICE); - goto error_handle; - } - - InitializeCriticalSection(&pComm->PendingEventsLock); - /* The binary/raw mode is required for the redirection but * only flags that are not handle somewhere-else, except * ICANON, are forced here. */ diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 14e862235..aac9e7a52 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -24,7 +24,6 @@ #ifndef _WIN32 #include -#include #include @@ -62,15 +61,10 @@ struct winpr_comm COMMTIMEOUTS timeouts; - /* NB: no synchronization required on counters until _get_commstatus() - * is the only function [except CreateFile() and CloseHandle()] to - * modify counters */ + CRITICAL_SECTION EventsLock; /* protects counters, WaitEventMask and PendingEvents */ struct serial_icounter_struct counters; - ULONG WaitEventMask; ULONG PendingEvents; - sem_t PendingEventsSem; - CRITICAL_SECTION PendingEventsLock; /* NB: CloseHandle() has to free resources */ }; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index ea87e353c..30792c792 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -1014,16 +1013,19 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) { ULONG possibleMask; + /* NB: ensure to leave the critical section before to return */ + EnterCriticalSection(&pComm->EventsLock); + if (*pWaitMask == 0) { /* clearing pending events */ - // TMP: TODO: - if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0) { DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); return FALSE; } @@ -1033,12 +1035,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) /* Stops pending IOCTL_SERIAL_WAIT_ON_MASK * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx */ - EnterCriticalSection(&pComm->PendingEventsLock); pComm->PendingEvents |= SERIAL_EV_FREERDP_STOP; - sem_post(&pComm->PendingEventsSem); - LeaveCriticalSection(&pComm->PendingEventsLock); - - possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK; @@ -1048,10 +1045,14 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) /* FIXME: shall we really set the possibleMask and return FALSE? */ pComm->WaitEventMask = possibleMask; + + LeaveCriticalSection(&pComm->EventsLock); return FALSE; } pComm->WaitEventMask = possibleMask; + + LeaveCriticalSection(&pComm->EventsLock); return TRUE; } @@ -1161,7 +1162,8 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) struct serial_icounter_struct currentCounters; - EnterCriticalSection(&pComm->PendingEventsLock); + /* NB: ensure to leave the critical section before to return */ + EnterCriticalSection(&pComm->EventsLock); ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS)); @@ -1170,6 +1172,8 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) { DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); return FALSE; } @@ -1215,6 +1219,8 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) { DEBUG_WARN("TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); return FALSE; } @@ -1225,6 +1231,8 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) { DEBUG_WARN("TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); return FALSE; } @@ -1285,8 +1293,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) pComm->counters = currentCounters; - LeaveCriticalSection(&pComm->PendingEventsLock); - + LeaveCriticalSection(&pComm->EventsLock); return TRUE; } @@ -1319,7 +1326,6 @@ static void _consume_event(WINPR_COMM *pComm, ULONG *pOutputMask, ULONG event) */ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) { - assert(*pOutputMask == 0); /* UGLY: removes the STOP bit set by an initial _set_wait_mask() */ @@ -1327,17 +1333,29 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) while (TRUE) { - struct timespec ts; - + /* NB: EventsLock also used by _refresh_PendingEvents() */ if (!_refresh_PendingEvents(pComm)) { return FALSE; } + /* NB: ensure to leave the critical section before to return */ + EnterCriticalSection(&pComm->EventsLock); - /* events */ + if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) + { + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; - EnterCriticalSection(&pComm->PendingEventsLock); + /* pOutputMask must remain empty but should + * not have been modified. + * + * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + */ + assert(*pOutputMask == 0); + + LeaveCriticalSection(&pComm->EventsLock); + return TRUE; + } _consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR); _consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG); @@ -1350,7 +1368,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) _consume_event(pComm, pOutputMask, SERIAL_EV_RING ); _consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL); - LeaveCriticalSection(&pComm->PendingEventsLock); + LeaveCriticalSection(&pComm->EventsLock); /* NOTE: PendingEvents can be modified from now on but * not pOutputMask */ @@ -1362,44 +1380,15 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) } - /* wait for 1 ms or a modification of PendingEvents */ + /* waiting for a modification of PendingEvents. + * + * NOTE: previously used a semaphore but used + * sem_timedwait() anyway. Finally preferred a simpler + * solution with Sleep() whithout the burden of the + * semaphore initialization and destroying. + */ - if (clock_gettime(CLOCK_REALTIME, &ts) < 0) - { - DEBUG_WARN("clock_realtime failed, errno=[%d] %s", errno, strerror(errno)); - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } - - ts.tv_nsec += 100000000; /* 100 ms */ - if (ts.tv_nsec > 999999999) - { - ts.tv_sec++; /* += 1s */ - ts.tv_nsec -= 1000000000; /* -= 1s */ - } - if (sem_timedwait(&pComm->PendingEventsSem, &ts) < 0) - { - assert(errno == ETIMEDOUT); - - if (errno != ETIMEDOUT) - { - DEBUG_WARN("sem_timedwait failed, errno=[%d] %s", errno, strerror(errno)); - SetLastError(ERROR_IO_DEVICE); - return FALSE; - } - } - - if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) - { - EnterCriticalSection(&pComm->PendingEventsLock); - pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; - LeaveCriticalSection(&pComm->PendingEventsLock); - - /* pOutputMask must remain empty - * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx - */ - return TRUE; - } + Sleep(100); /* 100 ms */ } DEBUG_WARN("_wait_on_mask, unexpected return, WaitEventMask=0X%lX", pComm->WaitEventMask); diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 5a40d632a..ca5d8bae1 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -206,16 +206,15 @@ BOOL CloseHandle(HANDLE hObject) if (comm->fd > 0) close(comm->fd); - /* NOTE: avoided to add a dependency by using a - * function such as _stop_wait_on_mask() */ - EnterCriticalSection(&comm->PendingEventsLock); + /* NOTE: This is up to the caller of CloseHandle() to + * ensure there is no pending request. Sending + * SERIAL_EV_FREERDP_STOP anyway. Remove this code if + * you think otherwise. */ + EnterCriticalSection(&comm->EventsLock); comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; - sem_post(&comm->PendingEventsSem); - LeaveCriticalSection(&comm->PendingEventsLock); - - sem_destroy(&comm->PendingEventsSem); /* FIXME: might be too early? */ - - DeleteCriticalSection(&comm->PendingEventsLock); + LeaveCriticalSection(&comm->EventsLock); + + DeleteCriticalSection(&comm->EventsLock); free(comm); From 1aeca8fbc7366d253a63b2a34acfdba9b3a012ee Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 27 May 2014 16:17:47 +0200 Subject: [PATCH 39/61] - serial: terminates IRP threads more gracefully and avoiding warning messages. --- channels/serial/client/serial_main.c | 36 ++++++++++++++++++++++++++- winpr/libwinpr/comm/comm.h | 3 ++- winpr/libwinpr/comm/comm_serial_sys.c | 15 +++++++++++ winpr/libwinpr/handle/handle.c | 10 ++++---- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 0a9348857..ae077535f 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -50,6 +50,8 @@ #include #include +#include + #include #include #include @@ -696,6 +698,35 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) } +static void terminate_pending_irp_threads(SERIAL_DEVICE *serial) +{ + ULONG_PTR *ids; + int i, nbIds; + + nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids); + + DEBUG_SVC("Terminating %d IRP thread(s)", nbIds); + + for (i=0; iIrpThreads, (void*)id); + + TerminateThread(irpThread, 0); + + WaitForSingleObject(irpThread, INFINITE); + + CloseHandle(irpThread); + + DEBUG_SVC("IRP thread terminated, CompletionId %d", id); + } + + ListDictionary_Clear(serial->IrpThreads); +} + + static void* serial_thread_func(void* arg) { IRP* irp; @@ -711,7 +742,10 @@ static void* serial_thread_func(void* arg) break; if (message.id == WMQ_QUIT) + { + terminate_pending_irp_threads(serial); break; + } irp = (IRP*) message.wParam; @@ -748,7 +782,7 @@ static void serial_free(DEVICE* device) WLog_Print(serial->log, WLOG_DEBUG, "freeing"); MessageQueue_PostQuit(serial->MainIrpQueue, 0); - WaitForSingleObject(serial->MainThread, INFINITE); /* FIXME: might likely block on a pending Write or ioctl */ + WaitForSingleObject(serial->MainThread, INFINITE); CloseHandle(serial->MainThread); if (serial->hComm) diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index aac9e7a52..b382cdfa7 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -74,7 +74,8 @@ typedef struct winpr_comm WINPR_COMM; void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); /* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ -#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_STOP 0x4000 /* bit unused by SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_CLOSING 0x8000 /* bit unused by SERIAL_EV_* */ #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 30792c792..572cb6c86 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1016,6 +1016,11 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); + if (pComm->PendingEvents |= SERIAL_EV_FREERDP_CLOSING) + { + return TRUE; /* returns without complaining */ + } + if (*pWaitMask == 0) { /* clearing pending events */ @@ -1165,6 +1170,11 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); + if (pComm->PendingEvents & SERIAL_EV_FREERDP_CLOSING) + { + return TRUE; /* returns without complaining */ + } + ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS)); ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); @@ -1341,6 +1351,11 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_CLOSING) + { + return TRUE; /* returns without complaining */ + } if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) { diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index ca5d8bae1..4d777d265 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -203,19 +203,19 @@ BOOL CloseHandle(HANDLE hObject) comm = (WINPR_COMM*) Object; - if (comm->fd > 0) - close(comm->fd); - /* NOTE: This is up to the caller of CloseHandle() to * ensure there is no pending request. Sending * SERIAL_EV_FREERDP_STOP anyway. Remove this code if * you think otherwise. */ EnterCriticalSection(&comm->EventsLock); - comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; + comm->PendingEvents |= SERIAL_EV_FREERDP_CLOSING; LeaveCriticalSection(&comm->EventsLock); - + DeleteCriticalSection(&comm->EventsLock); + if (comm->fd > 0) + close(comm->fd); + free(comm); return TRUE; From ae3dd68b8803947738bc93598a52ab5eb41151df Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 27 May 2014 16:27:04 +0200 Subject: [PATCH 40/61] winpr-comm: fixed _set_wait_mask() on previous commit --- winpr/libwinpr/comm/comm_serial_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 572cb6c86..678aa74ee 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1016,7 +1016,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); - if (pComm->PendingEvents |= SERIAL_EV_FREERDP_CLOSING) + if (pComm->PendingEvents & SERIAL_EV_FREERDP_CLOSING) { return TRUE; /* returns without complaining */ } From b8d00e41c4bb73a6db294ee3c059ee38b353e349 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 27 May 2014 17:29:55 +0200 Subject: [PATCH 41/61] - winpr-comm: fixed again the synchronization arround PendingEvents. Prefer to wait for the end of _wait_on_mask() inside _set_wait_mask() --- winpr/libwinpr/comm/comm.h | 4 +- winpr/libwinpr/comm/comm_serial_sys.c | 55 ++++++++++++++++----------- winpr/libwinpr/handle/handle.c | 2 +- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index b382cdfa7..ac149133e 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -74,8 +74,8 @@ typedef struct winpr_comm WINPR_COMM; void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); /* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ -#define SERIAL_EV_FREERDP_STOP 0x4000 /* bit unused by SERIAL_EV_* */ -#define SERIAL_EV_FREERDP_CLOSING 0x8000 /* bit unused by SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit unused by SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 678aa74ee..4df984036 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1013,14 +1013,27 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) { ULONG possibleMask; + + /* Stops pending IOCTL_SERIAL_WAIT_ON_MASK + * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + */ + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + { + /* FIXME: any doubt on reading PendingEvents out of a critical section? */ + + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents |= SERIAL_EV_FREERDP_STOP; + LeaveCriticalSection(&pComm->EventsLock); + + /* waiting the end of the pending _wait_on_mask() */ + while (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + Sleep(10); /* 10ms */ + } + /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); - if (pComm->PendingEvents & SERIAL_EV_FREERDP_CLOSING) - { - return TRUE; /* returns without complaining */ - } - if (*pWaitMask == 0) { /* clearing pending events */ @@ -1037,11 +1050,6 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) pComm->PendingEvents = 0; } - /* Stops pending IOCTL_SERIAL_WAIT_ON_MASK - * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx - */ - pComm->PendingEvents |= SERIAL_EV_FREERDP_STOP; - possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK; if (possibleMask != *pWaitMask) @@ -1170,11 +1178,6 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); - if (pComm->PendingEvents & SERIAL_EV_FREERDP_CLOSING) - { - return TRUE; /* returns without complaining */ - } - ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS)); ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); @@ -1338,25 +1341,25 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) { assert(*pOutputMask == 0); - /* UGLY: removes the STOP bit set by an initial _set_wait_mask() */ - pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents |= SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); + while (TRUE) { /* NB: EventsLock also used by _refresh_PendingEvents() */ if (!_refresh_PendingEvents(pComm)) { + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); return FALSE; } /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); - if (pComm->PendingEvents & SERIAL_EV_FREERDP_CLOSING) - { - return TRUE; /* returns without complaining */ - } - if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) { pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; @@ -1368,6 +1371,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) */ assert(*pOutputMask == 0); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; LeaveCriticalSection(&pComm->EventsLock); return TRUE; } @@ -1391,6 +1395,10 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) if (*pOutputMask != 0) { /* at least an event occurred */ + + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); return TRUE; } @@ -1407,6 +1415,9 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) } DEBUG_WARN("_wait_on_mask, unexpected return, WaitEventMask=0X%lX", pComm->WaitEventMask); + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); assert(FALSE); return FALSE; } diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 4d777d265..e7ada73ba 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -208,7 +208,7 @@ BOOL CloseHandle(HANDLE hObject) * SERIAL_EV_FREERDP_STOP anyway. Remove this code if * you think otherwise. */ EnterCriticalSection(&comm->EventsLock); - comm->PendingEvents |= SERIAL_EV_FREERDP_CLOSING; + comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; LeaveCriticalSection(&comm->EventsLock); DeleteCriticalSection(&comm->EventsLock); From f959590bd2b351fee11dfbd1d490c70c3fd83080 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 10:44:52 +0200 Subject: [PATCH 42/61] winpr-comm: _get_commstatus() just some comments about HoldReasons. --- winpr/libwinpr/comm/comm_serial_sys.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 4df984036..ac2b0367b 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1224,7 +1224,22 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) } - /* HoldReasons TMP: TODO: see also _set_lines(), _clear_lines() the LCR register. */ + /* HoldReasons */ + + + /* TODO: SERIAL_TX_WAITING_FOR_CTS */ + + /* TODO: SERIAL_TX_WAITING_FOR_DSR */ + + /* TODO: SERIAL_TX_WAITING_FOR_DCD */ + + /* TODO: SERIAL_TX_WAITING_FOR_XON */ + + /* TODO: SERIAL_TX_WAITING_ON_BREAK, see LCR's bit 6 */ + + /* TODO: SERIAL_TX_WAITING_XOFF_SENT */ + + /* AmountInInQueue */ From 1e9e8b68bf7a79ace9527c7bda67bea95fbf0061 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 11:39:10 +0200 Subject: [PATCH 43/61] winpr-comm: got IOCTL_SERIAL_GET_DTRRTS --- winpr/include/winpr/comm.h | 4 ++-- winpr/libwinpr/comm/comm_ioctl.c | 22 ++++++++++++++++++++ winpr/libwinpr/comm/comm_ioctl.h | 8 ++++++++ winpr/libwinpr/comm/comm_sercx2_sys.c | 3 +++ winpr/libwinpr/comm/comm_sercx_sys.c | 3 +++ winpr/libwinpr/comm/comm_serial_sys.c | 29 ++++++++++++++++++++++----- 6 files changed, 62 insertions(+), 7 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index c7bc8babc..a2889d53c 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -433,7 +433,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 #define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 #define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 -/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */ +#define IOCTL_SERIAL_GET_DTRRTS 0x001B0078 /* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */ #define IOCTL_SERIAL_GET_COMMSTATUS 0x001B006C @@ -499,7 +499,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"}, {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, {IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"}, - // {IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"}, + {IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"}, {IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"}, {IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"}, // {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"}, diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index b9cddefa3..28c5ae521 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -558,6 +558,28 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } break; } + case IOCTL_SERIAL_GET_DTRRTS: + { + if (pRemoteSerialDriver->get_dtrrts) + { + ULONG *pMask = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->get_dtrrts(pComm, pMask)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index cf3f642c0..283e524b3 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -198,6 +198,13 @@ typedef struct _SERIAL_STATUS #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 NULL if not supported by the underlying remote driver. * @@ -233,6 +240,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index e2915dd64..2e16358a2 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -150,6 +150,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .set_break_off = NULL, .set_xoff = NULL, /* not supported by SerCx2.sys */ .set_xon = NULL, /* not supported by SerCx2.sys */ + .get_dtrrts = NULL, }; @@ -195,6 +196,8 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s() _SerCx2Sys.set_break_on = pSerialSys->set_break_on; _SerCx2Sys.set_break_off = pSerialSys->set_break_off; + _SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts; + return &_SerCx2Sys; } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 87b1d1dbe..11c0e4d5e 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -399,6 +399,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .set_break_off = NULL, .set_xoff = NULL, .set_xon = NULL, + .get_dtrrts = NULL, }; @@ -441,6 +442,8 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.set_xoff = pSerialSys->set_xoff; _SerCxSys.set_xon = pSerialSys->set_xon; + _SerCxSys.get_dtrrts = pSerialSys->get_dtrrts; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index ac2b0367b..c2f710790 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -163,9 +163,6 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) * implementation just relies on the Linux' implementation. */ - // TMP: TODO: - - if (pProperties->dwProvSpec1 != COMMPROP_INITIALIZED) { ZeroMemory(pProperties, sizeof(COMMPROP)); @@ -184,7 +181,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */ - /* FIXME: what about PST_RS232? */ + /* FIXME: what about PST_RS232? see also: serial_struct */ pProperties->dwProvSubType = PST_UNSPECIFIED; /* TMP: TODO: to be finalized */ @@ -205,7 +202,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->wSettableStopParity = STOPBITS_10 | /*STOPBITS_15 |*/ STOPBITS_20 | PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_MARK | PARITY_SPACE; - /* FIXME: could be implemented on top of N_TTY */ + /* FIXME: additional input and output buffers could be implemented on top of N_TTY */ pProperties->dwCurrentTxQueue = N_TTY_BUF_SIZE; pProperties->dwCurrentRxQueue = N_TTY_BUF_SIZE; @@ -1489,6 +1486,27 @@ static BOOL _set_xon(WINPR_COMM *pComm) } +BOOL _get_dtrrts(WINPR_COMM *pComm, ULONG *pMask) +{ + UINT32 lines=0; + if (ioctl(pComm->fd, TIOCMGET, &lines) < 0) + { + DEBUG_WARN("TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + *pMask = 0; + + if (!(lines & TIOCM_DTR)) + *pMask |= SERIAL_DTR_STATE; + if (!(lines & TIOCM_RTS)) + *pMask |= SERIAL_RTS_STATE; + + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1519,6 +1537,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_break_off = _set_break_off, .set_xoff = _set_xoff, .set_xon = _set_xon, + .get_dtrrts = _get_dtrrts, }; From 4715009965037803aa1554e91f79a59d08b03c9f Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 16:41:24 +0200 Subject: [PATCH 44/61] winpr-comm: completing _purge() on write operations (SERIAL_PURGE_TXABORT) winpr-comm: CommWriteFile, implemented the WriteTotalTimeout --- winpr/libwinpr/comm/comm.c | 17 ++++ winpr/libwinpr/comm/comm.h | 6 ++ winpr/libwinpr/comm/comm_io.c | 124 +++++++++++++++++++++----- winpr/libwinpr/comm/comm_serial_sys.c | 35 ++++++-- winpr/libwinpr/handle/handle.c | 6 ++ 5 files changed, 159 insertions(+), 29 deletions(-) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 742eac397..6b47b5069 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1124,6 +1124,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } + /* TMP: won't be required once fd_read, fd_read_event implemented */ /* Restore the blocking mode for upcoming read/write operations */ if (fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK) < 0) { @@ -1133,6 +1134,22 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } + pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK); + if (pComm->fd_write < 0) + { + DEBUG_WARN("failed to open fd_write, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + pComm->fd_write_event = eventfd(0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */ + if (pComm->fd_write_event < 0) + { + DEBUG_WARN("failed to open fd_write_event, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + /* TMP: TODO: FIXME: this information is at least needed for * get/set baud functions. Is it possible to pull this * information? Could be a command line argument. diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index ac149133e..0df4333b2 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -24,6 +24,7 @@ #ifndef _WIN32 #include +#include #include @@ -46,6 +47,9 @@ struct winpr_comm WINPR_HANDLE_DEF(); int fd; + + int fd_write; + int fd_write_event; /* as of today, only used by _purge() */ /* permissive mode on errors if TRUE (default is FALSE). * @@ -77,6 +81,8 @@ void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); #define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit unused by SERIAL_EV_* */ #define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ +#define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */ +#define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */ #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index 1d7ad919b..e17cc9110 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -23,6 +23,7 @@ #ifndef _WIN32 +#include #include #include #include @@ -262,7 +263,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; - COMMTIMEOUTS *pTimeouts; + struct timeval timeout, *pTimeout; if (hDevice == INVALID_HANDLE_VALUE) { @@ -295,37 +296,114 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite return TRUE; /* FIXME: or FALSE? */ } - // TMP: TODO: Timeouts - pTimeouts = &(pComm->timeouts); + /* ms */ + ULONGLONG Tmax = nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier + 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() */ + + pTimeout = NULL; /* no timeout if Tmax == 0 */ + if (Tmax > 0) + { + ZeroMemory(&timeout, sizeof(struct timeval)); + + timeout.tv_sec = Tmax / 1000; /* s */ + timeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + + pTimeout = &timeout; + } + while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite) { - ssize_t nbWritten; + int biggestFd = -1; + fd_set event_set, write_set; - nbWritten = write(pComm->fd, - lpBuffer + (*lpNumberOfBytesWritten), - nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); + biggestFd = pComm->fd_write; + if (pComm->fd_write_event > biggestFd) + biggestFd = pComm->fd_write_event; - if (nbWritten < 0) + FD_ZERO(&event_set); + FD_ZERO(&write_set); + + assert(pComm->fd_write_event < FD_SETSIZE); + assert(pComm->fd_write < FD_SETSIZE); + + FD_SET(pComm->fd_write_event, &event_set); + FD_SET(pComm->fd_write, &write_set); + + if (select(biggestFd+1, &event_set, &write_set, NULL, pTimeout) < 0) { - DEBUG_WARN("CommWriteFile failed after %lu bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); - - switch (errno) - { - case EAGAIN: - /* EWOULDBLOCK */ - // TMP: FIXME: fcntl(tty->fd, F_SETFL, O_NONBLOCK) and manage the timeout here? - break; - case EBADF: - SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ - return FALSE; - } - + DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); return FALSE; } - *lpNumberOfBytesWritten += nbWritten; - } + + /* event_set */ + + if (FD_ISSET(pComm->fd_write_event, &event_set)) + { + eventfd_t event = 0; + int nbRead; + + nbRead = eventfd_read(pComm->fd_write_event, &event); + if (nbRead < 0) + { + if (errno == EAGAIN) + { + assert(FALSE); /* not quite sure this should ever happen */ + } + else + { + DEBUG_WARN("unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno)); + /* FIXME: return FALSE ? */ + } + + assert(errno == EAGAIN); + } + + assert(nbRead == sizeof(eventfd_t)); + + if (event == FREERDP_PURGE_TXABORT) + { + SetLastError(ERROR_CANCELLED); + return FALSE; + } + + assert(event == FREERDP_PURGE_TXABORT); /* no other event known so far */ + } + + + /* write_set */ + + if (FD_ISSET(pComm->fd_write, &write_set)) + { + ssize_t nbWritten; + + nbWritten = write(pComm->fd_write, + lpBuffer + (*lpNumberOfBytesWritten), + nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); + + if (nbWritten < 0) + { + DEBUG_WARN("CommWriteFile failed after %lu bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); + + if (errno == EAGAIN) + { + + } + else if (errno == EBADF) + { + SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ + return FALSE; + } + } + + *lpNumberOfBytesWritten += nbWritten; + } + + } /* while */ /* FIXME: this call to tcdrain() doesn't look correct and diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index c2f710790..1240d920c 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1114,24 +1114,47 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) return FALSE; } + /* FIXME: currently relying too much on the fact the server + * sends a single IRP_MJ_WRITE or IRP_MJ_READ at a time + * (taking care though that one IRP_MJ_WRITE and one + * IRP_MJ_READ can be sent simultaneously) */ if (*pPurgeMask & SERIAL_PURGE_TXABORT) { /* Purges all write (IRP_MJ_WRITE) requests. */ + int nbWritten; - // TMP: TODO: intercept this call before CommDeviceIoControl() ? - // getting a fd_write, fd_read and fs_iotcl? + if ((nbWritten = eventfd_write(pComm->fd_write_event, FREERDP_PURGE_TXABORT)) < 0) + { + if (errno != EAGAIN) + { + DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); + } + + assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_WRITE */ + } + + assert(nbWritten == sizeof(eventfd_t)); } if (*pPurgeMask & SERIAL_PURGE_RXABORT) { /* Purges all read (IRP_MJ_READ) requests. */ - /* TMP: TODO: double check if this gives well a change to abort a pending CommReadFile */ - /* assert(0); */ - /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) | O_NONBLOCK); */ - /* fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK); */ + /* int nbWritten; */ + + /* if ((nbWritten = eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT)) < 0) */ + /* { */ + /* if (errno != EAGAIN) */ + /* { */ + /* DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); */ + /* } */ + + /* assert(errno == EAGAIN); /\* no reader <=> no pending IRP_MJ_READ *\/ */ + /* } */ + + /* assert(nbWritten == 8); */ } if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index e7ada73ba..42a6c4bcc 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -216,6 +216,12 @@ BOOL CloseHandle(HANDLE hObject) if (comm->fd > 0) close(comm->fd); + if (comm->fd_write > 0) + close(comm->fd_write); + + if (comm->fd_write_event > 0) + close(comm->fd_write_event); + free(comm); return TRUE; From cdbba47eee87f9043e18d77e05741be3dc559db0 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 17:18:33 +0200 Subject: [PATCH 45/61] winpr-comm: CommWriteFile, completed support of WriteTotalTimeout --- channels/serial/client/serial_main.c | 10 +++++++++- winpr/libwinpr/comm/comm_io.c | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index ae077535f..90b8fe9be 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -265,7 +265,11 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) case ERROR_BAD_DEVICE: irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; break; - + + case ERROR_CANCELLED: + irp->IoStatus = STATUS_CANCELLED; + break; + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -342,6 +346,10 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; break; + case ERROR_CANCELLED: + irp->IoStatus = STATUS_CANCELLED; + break; + default: DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index e17cc9110..29eb0a103 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -318,6 +318,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite { int biggestFd = -1; fd_set event_set, write_set; + int nbFds; biggestFd = pComm->fd_write; if (pComm->fd_write_event > biggestFd) @@ -332,13 +333,22 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite FD_SET(pComm->fd_write_event, &event_set); FD_SET(pComm->fd_write, &write_set); - if (select(biggestFd+1, &event_set, &write_set, NULL, pTimeout) < 0) + nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTimeout); + if (nbFds < 0) { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); return FALSE; } + if (nbFds == 0) + { + /* timeout */ + + SetLastError(ERROR_TIMEOUT); + return FALSE; + } + /* event_set */ @@ -391,7 +401,8 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite if (errno == EAGAIN) { - + /* keep on */ + continue; } else if (errno == EBADF) { From 85343a435a5c85ea6751971c0c7f9046a6a25b73 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 18:42:23 +0200 Subject: [PATCH 46/61] winpr-comm: completed _purge() supporting SERIAL_PURGE_RXABORT winpr-comm: CommReadFile, support of FREERDP_PURGE_RXABORT sent by _purge() --- winpr/libwinpr/comm/comm.c | 14 ++- winpr/libwinpr/comm/comm.h | 3 + winpr/libwinpr/comm/comm_io.c | 153 ++++++++++++++++++++------ winpr/libwinpr/comm/comm_serial_sys.c | 20 ++-- winpr/libwinpr/handle/handle.c | 6 + 5 files changed, 150 insertions(+), 46 deletions(-) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 6b47b5069..756457bff 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1124,15 +1124,21 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } - /* TMP: won't be required once fd_read, fd_read_event implemented */ - /* Restore the blocking mode for upcoming read/write operations */ - if (fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK) < 0) + pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK); + if (pComm->fd_read < 0) { - DEBUG_WARN("failed to open device %s, could not restore the O_NONBLOCK flag", devicePath); + DEBUG_WARN("failed to open fd_read, device: %s", devicePath); SetLastError(ERROR_BAD_DEVICE); goto error_handle; } + pComm->fd_read_event = eventfd(0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */ + if (pComm->fd_read_event < 0) + { + DEBUG_WARN("failed to open fd_read_event, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK); if (pComm->fd_write < 0) diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 0df4333b2..d856448df 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -47,6 +47,9 @@ struct winpr_comm WINPR_HANDLE_DEF(); int fd; + + int fd_read; + int fd_read_event; /* as of today, only used by _purge() */ int fd_write; int fd_write_event; /* as of today, only used by _purge() */ diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index 29eb0a103..6516535e9 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -45,7 +45,7 @@ BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive) return FALSE; } - if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; @@ -89,6 +89,9 @@ 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; ssize_t nbRead = 0; COMMTIMEOUTS *pTimeouts; UCHAR vmin = 0; @@ -101,7 +104,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, return FALSE; } - if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; @@ -143,7 +146,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, * 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 | 0 | Blocks for N bytes available. FIXME: reduce N to 1? + * 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available. * 0< Ti fd, TCSANOW, ¤tTermios) < 0) { @@ -218,37 +221,116 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } } - nbRead = read(pComm->fd, lpBuffer, nNumberOfBytesToRead); - if (nbRead < 0) + + + + biggestFd = pComm->fd_read; + if (pComm->fd_read_event > biggestFd) + biggestFd = pComm->fd_read_event; + + FD_ZERO(&read_set); + + assert(pComm->fd_read_event < FD_SETSIZE); + 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, NULL, NULL, NULL /* TMP: TODO:*/); + if (nbFds < 0) { - DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u", - pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, - currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); - DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); - - switch (errno) - { - // TMP: TODO: - case EAGAIN: /* EWOULDBLOCK */ - nbRead = 0; - break; - - case EBADF: - SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ - return FALSE; - - default: - return FALSE; - } + DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (nbFds == 0) + { + /* timeout */ + SetLastError(ERROR_TIMEOUT); + return FALSE; } - // TODO: - // SetLastError(ERROR_TIMEOUT) - *lpNumberOfBytesRead = nbRead; - return TRUE; + /* read_set */ + + if (FD_ISSET(pComm->fd_read_event, &read_set)) + { + eventfd_t event = 0; + int nbRead; + + nbRead = eventfd_read(pComm->fd_read_event, &event); + if (nbRead < 0) + { + if (errno == EAGAIN) + { + assert(FALSE); /* not quite sure this should ever happen */ + /* keep on */ + } + else + { + DEBUG_WARN("unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno)); + /* FIXME: return FALSE ? */ + } + + assert(errno == EAGAIN); + } + + assert(nbRead == sizeof(eventfd_t)); + + if (event == FREERDP_PURGE_RXABORT) + { + SetLastError(ERROR_CANCELLED); + return FALSE; + } + + assert(event == FREERDP_PURGE_RXABORT); /* no other expected event so far */ + } + + if (FD_ISSET(pComm->fd_read, &read_set)) + { + nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead); + if (nbRead < 0) + { + DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u", + pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, + currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); + DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); + + if (errno == EAGAIN) + { + /* keep on */ + 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 */ + return FALSE; + } + else + { + assert(FALSE); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + } + + if (nbRead == 0) + { + /* termios timeout */ + SetLastError(ERROR_TIMEOUT); + return FALSE; + } + + *lpNumberOfBytesRead = nbRead; + return TRUE; + } + + assert(FALSE); + *lpNumberOfBytesRead = 0; + return FALSE; } @@ -271,7 +353,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite return FALSE; } - if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; @@ -363,6 +445,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite if (errno == EAGAIN) { assert(FALSE); /* not quite sure this should ever happen */ + /* keep on */ } else { @@ -381,7 +464,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite return FALSE; } - assert(event == FREERDP_PURGE_TXABORT); /* no other event known so far */ + assert(event == FREERDP_PURGE_TXABORT); /* no other expected event so far */ } @@ -409,6 +492,12 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ return FALSE; } + else + { + assert(FALSE); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } } *lpNumberOfBytesWritten += nbWritten; @@ -425,7 +514,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite * Write operation. The serial port was oppened with: * DesiredAccess=0x0012019F. The printer worked fine with * mstsc. */ - tcdrain(pComm->fd); + tcdrain(pComm->fd_write); return TRUE; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 1240d920c..61de95692 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1142,19 +1142,19 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { /* Purges all read (IRP_MJ_READ) requests. */ - /* int nbWritten; */ + int nbWritten; - /* if ((nbWritten = eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT)) < 0) */ - /* { */ - /* if (errno != EAGAIN) */ - /* { */ - /* DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); */ - /* } */ + if ((nbWritten = eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT)) < 0) + { + if (errno != EAGAIN) + { + DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); + } - /* assert(errno == EAGAIN); /\* no reader <=> no pending IRP_MJ_READ *\/ */ - /* } */ + assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */ + } - /* assert(nbWritten == 8); */ + assert(nbWritten == sizeof(eventfd_t)); } if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 42a6c4bcc..d2523e43e 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -222,6 +222,12 @@ BOOL CloseHandle(HANDLE hObject) if (comm->fd_write_event > 0) close(comm->fd_write_event); + if (comm->fd_read > 0) + close(comm->fd_read); + + if (comm->fd_read_event > 0) + close(comm->fd_read_event); + free(comm); return TRUE; From f26c7ee4980c8799d8dd4938c625ebea0384264d Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 19:10:01 +0200 Subject: [PATCH 47/61] winpr-comm: fixed _purge(), eventfd_read() and eventfd_write() just return a error code, not a number of bytes read or written --- winpr/libwinpr/comm/comm_io.c | 12 ++---------- winpr/libwinpr/comm/comm_serial_sys.c | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index 6516535e9..0439800b1 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -259,10 +259,8 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (FD_ISSET(pComm->fd_read_event, &read_set)) { eventfd_t event = 0; - int nbRead; - nbRead = eventfd_read(pComm->fd_read_event, &event); - if (nbRead < 0) + if (eventfd_read(pComm->fd_read_event, &event) < 0) { if (errno == EAGAIN) { @@ -278,8 +276,6 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, assert(errno == EAGAIN); } - assert(nbRead == sizeof(eventfd_t)); - if (event == FREERDP_PURGE_RXABORT) { SetLastError(ERROR_CANCELLED); @@ -437,10 +433,8 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite if (FD_ISSET(pComm->fd_write_event, &event_set)) { eventfd_t event = 0; - int nbRead; - nbRead = eventfd_read(pComm->fd_write_event, &event); - if (nbRead < 0) + if (eventfd_read(pComm->fd_write_event, &event) < 0) { if (errno == EAGAIN) { @@ -456,8 +450,6 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite assert(errno == EAGAIN); } - assert(nbRead == sizeof(eventfd_t)); - if (event == FREERDP_PURGE_TXABORT) { SetLastError(ERROR_CANCELLED); diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 61de95692..4c90c65b5 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1123,9 +1123,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { /* Purges all write (IRP_MJ_WRITE) requests. */ - int nbWritten; - - if ((nbWritten = eventfd_write(pComm->fd_write_event, FREERDP_PURGE_TXABORT)) < 0) + if (eventfd_write(pComm->fd_write_event, FREERDP_PURGE_TXABORT) < 0) { if (errno != EAGAIN) { @@ -1134,17 +1132,13 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_WRITE */ } - - assert(nbWritten == sizeof(eventfd_t)); } if (*pPurgeMask & SERIAL_PURGE_RXABORT) { /* Purges all read (IRP_MJ_READ) requests. */ - int nbWritten; - - if ((nbWritten = eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT)) < 0) + if (eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT) < 0) { if (errno != EAGAIN) { @@ -1153,8 +1147,6 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */ } - - assert(nbWritten == sizeof(eventfd_t)); } if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) From 16b6c44ef730971be09e13745b7ea15245b4b24f Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 20:15:08 +0200 Subject: [PATCH 48/61] winpr-comm: need to purge _purge()'s events before read and write operations --- winpr/libwinpr/comm/comm_io.c | 20 ++++++++++++++------ winpr/libwinpr/comm/comm_serial_sys.c | 6 +++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index 0439800b1..cf965d5a1 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -92,7 +92,6 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, int biggestFd = -1; fd_set read_set; int nbFds; - ssize_t nbRead = 0; COMMTIMEOUTS *pTimeouts; UCHAR vmin = 0; UCHAR vtime = 0; @@ -211,7 +210,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, currentTermios.c_cc[VTIME] = vtime; // TMP: - fprintf(stderr, "Applying timeout VMIN=%u, VTIME=%u", vmin, vtime); + fprintf(stderr, "MANU: Applying timeout VMIN=%u, VTIME=%u\n", vmin, vtime); if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0) { @@ -221,9 +220,10 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } } - - - + /* 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 */ + eventfd_read(pComm->fd_read_event, NULL); biggestFd = pComm->fd_read; if (pComm->fd_read_event > biggestFd) @@ -269,7 +269,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } else { - DEBUG_WARN("unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno)); + DEBUG_WARN("unexpected error on reading fd_read_event, errno=[%d] %s\n", errno, strerror(errno)); /* FIXME: return FALSE ? */ } @@ -287,6 +287,8 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (FD_ISSET(pComm->fd_read, &read_set)) { + ssize_t nbRead = 0; + nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead); if (nbRead < 0) { @@ -374,6 +376,12 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite 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 */ + eventfd_read(pComm->fd_write_event, NULL); + + /* ms */ ULONGLONG Tmax = nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier + pComm->timeouts.WriteTotalTimeoutConstant; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 4c90c65b5..d83d0cfae 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1095,10 +1095,10 @@ static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSi /* FIXME: could be implemented on top of N_TTY */ if (pQueueSize->InSize > N_TTY_BUF_SIZE) - DEBUG_WARN("Requested an incompatible input buffer size: %lu", pQueueSize->InSize); + DEBUG_WARN("Requested an incompatible input buffer size: %lu, keeping on with a %lu bytes buffer.", pQueueSize->InSize, N_TTY_BUF_SIZE); if (pQueueSize->OutSize > N_TTY_BUF_SIZE) - DEBUG_WARN("Requested an incompatible output buffer size: %lu", pQueueSize->OutSize); + DEBUG_WARN("Requested an incompatible output buffer size: %lu, keeping on with a %lu bytes buffer.", pQueueSize->OutSize, N_TTY_BUF_SIZE); SetLastError(ERROR_CANCELLED); return FALSE; @@ -1144,7 +1144,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); } - + assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */ } } From 50efce67f538212a04273ad447b453f6210a11db Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 22:11:19 +0200 Subject: [PATCH 49/61] winpr-comm: completed support of Read*Timeout --- channels/serial/client/serial_main.c | 19 ++--- winpr/libwinpr/comm/comm_io.c | 114 +++++++++++++++------------ 2 files changed, 67 insertions(+), 66 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 90b8fe9be..fe9a4d515 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -163,15 +163,6 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) /* dcb.fBinary = TRUE; */ /* SetCommState(serial->hComm, &dcb); */ - // TMP: - COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = MAXULONG; /* ensures a non blocking state */ - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(serial->hComm, &timeouts); - assert(irp->FileId == 0); irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */ @@ -238,7 +229,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8x", serial->device.name, nbRead, GetLastError()); + DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8X", serial->device.name, nbRead, GetLastError()); switch(GetLastError()) { @@ -319,7 +310,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8x", serial->device.name, nbWritten, GetLastError()); + DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8X", serial->device.name, nbWritten, GetLastError()); switch(GetLastError()) { case ERROR_INVALID_HANDLE: @@ -351,7 +342,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) break; default: - DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + DEBUG_SVC("unexpected last-error: 0x%X", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; break; } @@ -405,7 +396,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%x", + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%X", IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); // TMP: TODO: Status codes to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests @@ -445,7 +436,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) break; default: - DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + DEBUG_SVC("unexpected last-error: 0x%X", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; break; } diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index cf965d5a1..27719c923 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -56,23 +56,19 @@ BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive) } -/* Computes Tmax in deciseconds (m and Tcare in milliseconds) */ -static UCHAR _tmax(DWORD N, ULONG m, ULONG Tc) +/* Computes VMIN in deciseconds from Ti in milliseconds */ +static UCHAR _vtime(ULONG Ti) { - /* Tmax = N * m + Tc */ - - ULONGLONG Tmax = N * m + Tc; - /* FIXME: look for an equivalent math function otherwise let * do the compiler do the optimization */ - if (Tmax == 0) + if (Ti == 0) return 0; - else if (Tmax < 100) + else if (Ti < 100) return 1; - else if (Tmax > 25500) + else if (Ti > 25500) return 255; /* 0xFF */ else - return Tmax/100; + return Ti/100; } @@ -95,6 +91,8 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, COMMTIMEOUTS *pTimeouts; UCHAR vmin = 0; UCHAR vtime = 0; + ULONGLONG Tmax = 0; + struct timeval tmaxTimeout, *pTmaxTimeout; struct termios currentTermios; if (hDevice == INVALID_HANDLE_VALUE) @@ -144,24 +142,19 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* 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 | 0 | Blocks for N bytes available. - * 0< Ti fd, O_NONBLOCK) doesn't conflict with above use cases - */ + /* FIXME: double check whether open(pComm->fd_read_event, O_NONBLOCK) doesn't conflict with above use cases */ pTimeouts = &(pComm->timeouts); @@ -174,44 +167,49 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* VMIN */ - if ((pTimeouts->ReadIntervalTimeout < MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) { - /* should only match the two first cases above */ - vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255; /* 0xFF */ + 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->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG)) { /* Ti */ - - vtime = _tmax(0, 0, pTimeouts->ReadIntervalTimeout); - + vtime = _vtime(pTimeouts->ReadIntervalTimeout); } - else if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant < MAXULONG)) + + + /* TMAX */ + + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG)) { /* Tc */ - - vtime = _tmax(0, 0, pTimeouts->ReadTotalTimeoutConstant); + Tmax = pTimeouts->ReadTotalTimeoutConstant; } - else if ((pTimeouts->ReadTotalTimeoutMultiplier > 0) || (pTimeouts->ReadTotalTimeoutConstant > 0)) /* <=> Tmax > 0 */ + else { - /* Tmax and Tmax(1) */ - - vtime = _tmax(nNumberOfBytesToRead, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant); + /* Tmax */ + Tmax = nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier + pTimeouts->ReadTotalTimeoutConstant; } - if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime)) { currentTermios.c_cc[VMIN] = vmin; currentTermios.c_cc[VTIME] = vtime; - // TMP: - fprintf(stderr, "MANU: Applying timeout VMIN=%u, VTIME=%u\n", vmin, vtime); - if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0) { DEBUG_WARN("CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime); @@ -220,6 +218,18 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } } + pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */ + if (Tmax > 0) + { + ZeroMemory(&tmaxTimeout, sizeof(struct timeval)); + + tmaxTimeout.tv_sec = Tmax / 1000; /* s */ + tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + + pTmaxTimeout = &tmaxTimeout; + } + + /* 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 */ @@ -237,7 +247,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, FD_SET(pComm->fd_read_event, &read_set); FD_SET(pComm->fd_read, &read_set); - nbFds = select(biggestFd+1, &read_set, NULL, NULL, NULL /* TMP: TODO:*/); + nbFds = select(biggestFd+1, &read_set, NULL, NULL, pTmaxTimeout); if (nbFds < 0) { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); @@ -321,7 +331,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, SetLastError(ERROR_TIMEOUT); return FALSE; } - + *lpNumberOfBytesRead = nbRead; return TRUE; } @@ -343,7 +353,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; - struct timeval timeout, *pTimeout; + struct timeval tmaxTimeout, *pTmaxTimeout; if (hDevice == INVALID_HANDLE_VALUE) { @@ -389,15 +399,15 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite * how much time was left. Keep the timeout variable out of * the while() */ - pTimeout = NULL; /* no timeout if Tmax == 0 */ + pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */ if (Tmax > 0) { - ZeroMemory(&timeout, sizeof(struct timeval)); + ZeroMemory(&tmaxTimeout, sizeof(struct timeval)); - timeout.tv_sec = Tmax / 1000; /* s */ - timeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + tmaxTimeout.tv_sec = Tmax / 1000; /* s */ + tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */ - pTimeout = &timeout; + pTmaxTimeout = &tmaxTimeout; } while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite) @@ -419,7 +429,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite FD_SET(pComm->fd_write_event, &event_set); FD_SET(pComm->fd_write, &write_set); - nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTimeout); + nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTmaxTimeout); if (nbFds < 0) { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); From 0db3d9dbb022fd9d00463d5397296a57752532e6 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Mon, 16 Jun 2014 19:18:45 +0200 Subject: [PATCH 50/61] winpr-comm: cleaning up code, focused on indentation and whitespaces --- channels/serial/client/serial_main.c | 72 +++---- winpr/include/winpr/comm.h | 8 +- winpr/include/winpr/file.h | 1 - winpr/libwinpr/comm/comm.c | 58 +++--- winpr/libwinpr/comm/comm.h | 10 +- winpr/libwinpr/comm/comm_io.c | 44 ++-- winpr/libwinpr/comm/comm_ioctl.c | 60 +++--- winpr/libwinpr/comm/comm_ioctl.h | 188 +++++++++--------- winpr/libwinpr/comm/comm_sercx2_sys.c | 10 +- winpr/libwinpr/comm/comm_sercx2_sys.h | 6 +- winpr/libwinpr/comm/comm_sercx_sys.c | 14 +- winpr/libwinpr/comm/comm_sercx_sys.h | 6 +- winpr/libwinpr/comm/comm_serial_sys.c | 109 ++++------ winpr/libwinpr/comm/comm_serial_sys.h | 6 +- winpr/libwinpr/comm/test/TestCommConfig.c | 21 +- winpr/libwinpr/comm/test/TestCommDevice.c | 20 +- .../libwinpr/comm/test/TestControlSettings.c | 20 +- winpr/libwinpr/comm/test/TestGetCommState.c | 6 +- winpr/libwinpr/comm/test/TestHandflow.c | 4 +- winpr/libwinpr/comm/test/TestSerialChars.c | 8 +- winpr/libwinpr/comm/test/TestSetCommState.c | 6 +- winpr/libwinpr/comm/test/TestTimeouts.c | 4 +- 22 files changed, 320 insertions(+), 361 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index fe9a4d515..0d0d9a2dc 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -108,12 +108,12 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) #ifndef _WIN32 - /* Windows 2012 server sends on a first call : + /* Windows 2012 server sends on a first call : * DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ * CreateDisposition = 0x00000001: CREATE_NEW * - * then Windows 2012 sends : + * then Windows 2012 sends : * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ * CreateDisposition = 0x00000001: CREATE_NEW @@ -133,12 +133,12 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) #endif serial->hComm = CreateFile(serial->device.name, - DesiredAccess, - SharedAccess, - NULL, /* SecurityAttributes */ - CreateDisposition, - 0, /* FlagsAndAttributes */ - NULL); /* TemplateFile */ + DesiredAccess, + SharedAccess, + NULL, /* SecurityAttributes */ + CreateDisposition, + 0, /* FlagsAndAttributes */ + NULL); /* TemplateFile */ if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE)) { @@ -214,11 +214,11 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) goto error_handle; } - + /* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored * assert(Offset == 0); */ - + DEBUG_SVC("reading %lu bytes from %s", Length, serial->device.name); @@ -240,7 +240,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) case ERROR_NOT_SUPPORTED: irp->IoStatus = STATUS_NOT_SUPPORTED; break; - + case ERROR_INVALID_PARAMETER: irp->IoStatus = STATUS_INVALID_PARAMETER; break; @@ -269,7 +269,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) } DEBUG_SVC("%lu bytes read from %s", nbRead, serial->device.name); - + error_handle: Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */ @@ -320,7 +320,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) case ERROR_NOT_SUPPORTED: irp->IoStatus = STATUS_NOT_SUPPORTED; break; - + case ERROR_INVALID_PARAMETER: irp->IoStatus = STATUS_INVALID_PARAMETER; break; @@ -386,7 +386,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_Read(irp->input, InputBuffer, InputBufferLength); DEBUG_SVC("CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); - + /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) { @@ -396,8 +396,8 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%X", - IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%X", + IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); // TMP: TODO: Status codes to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests @@ -472,7 +472,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) { WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n", - irp->MajorFunction, irp->MinorFunction); + irp->MajorFunction, irp->MinorFunction); switch (irp->MajorFunction) { @@ -590,7 +590,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) } /* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */ } - + if (serial->IrpThreadToBeTerminatedCount > 0) { @@ -612,7 +612,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) */ previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)irp->CompletionId); - if (previousIrpThread) + if (previousIrpThread) { /* Thread still alived <=> Request still pending */ @@ -643,7 +643,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS) { DEBUG_WARN("Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads)); - + assert(FALSE); /* unimplemented */ /* TODO: MAX_IRP_THREADS has been thought to avoid a @@ -668,12 +668,12 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) /* data freed by irp_thread_func */ - irpThread = CreateThread(NULL, - 0, - (LPTHREAD_START_ROUTINE)irp_thread_func, - (void*)data, - 0, - NULL); + irpThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE)irp_thread_func, + (void*)data, + 0, + NULL); if (irpThread == INVALID_HANDLE_VALUE) { @@ -711,7 +711,7 @@ static void terminate_pending_irp_threads(SERIAL_DEVICE *serial) HANDLE irpThread; ULONG_PTR id = ids[i]; - irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id); + irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id); TerminateThread(irpThread, 0); @@ -777,7 +777,7 @@ static void serial_irp_request(DEVICE* device, IRP* irp) static void serial_free(DEVICE* device) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; - + WLog_Print(serial->log, WLOG_DEBUG, "freeing"); MessageQueue_PostQuit(serial->MainIrpQueue, 0); @@ -821,7 +821,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if ((name && name[0]) && (path && path[0])) { DEBUG_SVC("Defining %s as %s", name, path); - + if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) { DEBUG_SVC("Could not define %s as %s", name, path); @@ -846,7 +846,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->MainIrpQueue = MessageQueue_New(NULL); /* IrpThreads content only modified by create_irp_thread() */ - serial->IrpThreads = ListDictionary_New(FALSE); + serial->IrpThreads = ListDictionary_New(FALSE); serial->IrpThreadToBeTerminatedCount = 0; InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); @@ -856,12 +856,12 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); - serial->MainThread = CreateThread(NULL, - 0, - (LPTHREAD_START_ROUTINE) serial_thread_func, - (void*) serial, - 0, - NULL); + serial->MainThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE) serial_thread_func, + (void*) serial, + 0, + NULL); } return 0; diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index a2889d53c..9e5d67357 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -401,7 +401,7 @@ WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName); * RegisterHandleCreator(). */ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); @@ -546,19 +546,19 @@ BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive); * FIXME: to be moved in comm_ioctl.h */ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, - LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); /** * FIXME: to be moved in comm_io.h */ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); /** * FIXME: to be moved in comm_io.h */ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); #ifdef __cplusplus } diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index e90019be0..9f8d748a8 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -353,4 +353,3 @@ WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); #endif #endif /* WINPR_FILE_H */ - diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 756457bff..cbff32d55 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -5,7 +5,7 @@ * Copyright 2011 O.S. Systems Software Ltda. * Copyright 2011 Eduardo Fiss Beloni * Copyright 2014 Marc-Andre Moreau - * Copyright 2014 Hewlett-Packard Development Company, L.P. + * 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. @@ -158,7 +158,7 @@ BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp) /** - * + * * * ERRORS: * ERROR_INVALID_HANDLE @@ -205,7 +205,7 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) } /* error_handle */ - + lpLocalDcb->DCBlength = lpDCB->DCBlength; SERIAL_BAUD_RATE baudRate; @@ -215,14 +215,14 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) goto error_handle; } lpLocalDcb->BaudRate = baudRate.BaudRate; - + lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0; if (!lpLocalDcb->fBinary) { DEBUG_WARN("Unexpected nonbinary mode, consider to unset the ICANON flag."); } - lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; + lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; SERIAL_HANDFLOW handflow; if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow, sizeof(SERIAL_HANDFLOW), &bytesReturned, NULL)) @@ -250,7 +250,7 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0; - lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0; + lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0; lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0; @@ -314,7 +314,7 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) lpLocalDcb->ErrorChar = serialChars.ErrorChar; lpLocalDcb->EofChar = serialChars.EofChar; - + lpLocalDcb->EvtChar = serialChars.EventChar; @@ -332,7 +332,7 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) /** * @return TRUE on success, FALSE otherwise. - * + * * As of today, SetCommState() can fail half-way with some settings * applied and some others not. SetCommState() returns on the first * failure met. FIXME: or is it correct? @@ -384,7 +384,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) serialChars.XoffChar = lpDCB->XoffChar; serialChars.ErrorChar = lpDCB->ErrorChar; serialChars.EofChar = lpDCB->EofChar; - serialChars.EventChar = lpDCB->EvtChar; + serialChars.EventChar = lpDCB->EvtChar; if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars, sizeof(SERIAL_CHARS), NULL, 0, &bytesReturned, NULL)) { DEBUG_WARN("SetCommState failure: could not set the serial chars."); @@ -409,7 +409,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) { handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE; } - + if (lpDCB->fOutxDsrFlow) { @@ -444,7 +444,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) { handflow.FlowReplace |= SERIAL_XOFF_CONTINUE; } - + if (lpDCB->fOutX) { handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT; @@ -551,13 +551,13 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) * * TCSANOW matches the best this definition */ - + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) { SetLastError(ERROR_IO_DEVICE); return FALSE; } - + return TRUE; } @@ -744,7 +744,7 @@ BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) /* Extended API */ -typedef struct _COMM_DEVICE +typedef struct _COMM_DEVICE { LPTSTR name; LPTSTR path; @@ -760,11 +760,11 @@ static HANDLE_CREATOR *_CommHandleCreator = NULL; static void _CommDevicesInit() { - /* + /* * TMP: FIXME: What kind of mutex should be used here? * better have to let DefineCommDevice() and QueryCommDevice() thread unsafe ? * use of a module_init() ? - */ + */ if (_CommDevices == NULL) { @@ -818,7 +818,7 @@ static BOOL _IsReservedCommDeviceName(LPCTSTR lpName) /** * Returns TRUE on success, FALSE otherwise. To get extended error * information, call GetLastError. - * + * * ERRORS: * ERROR_OUTOFMEMORY was not possible to get mappings. * ERROR_INVALID_DATA was not possible to add the device. @@ -912,12 +912,12 @@ BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTarget /** * Returns the number of target paths in the buffer pointed to by - * lpTargetPath. + * lpTargetPath. * * The current implementation returns in any case 0 and 1 target * path. A NULL lpDeviceName is not supported yet to get all the * paths. - * + * * ERRORS: * ERROR_SUCCESS * ERROR_OUTOFMEMORY was not possible to get mappings. @@ -961,7 +961,7 @@ DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) break; } - + if (storedTargetPath == NULL) { SetLastError(ERROR_INVALID_DATA); @@ -981,7 +981,7 @@ DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) } /** - * Checks whether lpDeviceName is a valid and registered Communication device. + * Checks whether lpDeviceName is a valid and registered Communication device. */ BOOL IsCommDevice(LPCTSTR lpDeviceName) { @@ -997,7 +997,7 @@ BOOL IsCommDevice(LPCTSTR lpDeviceName) /** - * Sets + * Sets */ void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID driverId) { @@ -1026,10 +1026,10 @@ void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID driverId) * * @param dwShareMode must be zero, INVALID_HANDLE_VALUE is returned * otherwise and GetLastError() should return ERROR_SHARING_VIOLATION. - * + * * @param lpSecurityAttributes NULL expected, a warning message is printed * otherwise. TODO: better support. - * + * * @param dwCreationDisposition must be OPEN_EXISTING. If the * communication device doesn't exist INVALID_HANDLE_VALUE is returned * and GetLastError() returns ERROR_FILE_NOT_FOUND. @@ -1039,16 +1039,16 @@ void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID driverId) * * @param hTemplateFile must be NULL. * - * @return INVALID_HANDLE_VALUE on error. + * @return INVALID_HANDLE_VALUE on error. */ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { CHAR devicePath[MAX_PATH]; struct stat deviceStat; WINPR_COMM* pComm = NULL; struct termios upcomingTermios; - + if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE)) { DEBUG_WARN("unexpected access to the device: 0x%lX", dwDesiredAccess); @@ -1073,7 +1073,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare SetLastError(ERROR_FILE_NOT_FOUND); /* FIXME: ERROR_NOT_SUPPORTED better? */ return INVALID_HANDLE_VALUE; } - + if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0) { /* SetLastError(GetLastError()); */ @@ -1194,7 +1194,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare * IGNBRK and IXON, see: IOCTL_SERIAL_SET_HANDFLOW * CSIZE, PARENB and CS8, see: IOCTL_SERIAL_SET_LINE_CONTROL */ - + /* a few more settings required for the redirection */ upcomingTermios.c_cflag |= CLOCAL | CREAD; diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index d856448df..950ef19a1 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -3,7 +3,7 @@ * Serial Communication API * * Copyright 2014 Marc-Andre Moreau - * Copyright 2014 Hewlett-Packard Development Company, L.P. + * 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. @@ -50,11 +50,11 @@ struct winpr_comm int fd_read; int fd_read_event; /* as of today, only used by _purge() */ - + int fd_write; int fd_write_event; /* as of today, only used by _purge() */ - /* permissive mode on errors if TRUE (default is FALSE). + /* permissive mode on errors if TRUE (default is FALSE). * * Since not all features are supported, some devices and applications * can still be functional on such errors. @@ -67,7 +67,7 @@ struct winpr_comm REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; COMMTIMEOUTS timeouts; - + CRITICAL_SECTION EventsLock; /* protects counters, WaitEventMask and PendingEvents */ struct serial_icounter_struct counters; ULONG WaitEventMask; @@ -82,7 +82,7 @@ void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); /* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ #define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit unused by SERIAL_EV_* */ -#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ #define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */ #define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */ diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index 27719c923..bfce8d3e5 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -82,7 +82,7 @@ static UCHAR _vtime(ULONG Ti) * ERROR_BAD_DEVICE */ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; int biggestFd = -1; @@ -146,9 +146,9 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, * 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available. * 0< Ti ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG)) { /* Tc */ @@ -204,7 +204,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* Tmax */ Tmax = nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier + pTimeouts->ReadTotalTimeoutConstant; } - + if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime)) { currentTermios.c_cc[VMIN] = vmin; @@ -254,7 +254,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, SetLastError(ERROR_IO_DEVICE); return FALSE; } - + if (nbFds == 0) { /* timeout */ @@ -303,8 +303,8 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (nbRead < 0) { DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u", - pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, - currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); + pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, + currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); if (errno == EAGAIN) @@ -331,7 +331,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, SetLastError(ERROR_TIMEOUT); return FALSE; } - + *lpNumberOfBytesRead = nbRead; return TRUE; } @@ -350,7 +350,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, * ERROR_BAD_DEVICE */ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; struct timeval tmaxTimeout, *pTmaxTimeout; @@ -409,7 +409,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite pTmaxTimeout = &tmaxTimeout; } - + while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite) { int biggestFd = -1; @@ -444,7 +444,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite SetLastError(ERROR_TIMEOUT); return FALSE; } - + /* event_set */ @@ -479,15 +479,15 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite /* write_set */ - + if (FD_ISSET(pComm->fd_write, &write_set)) { ssize_t nbWritten; - nbWritten = write(pComm->fd_write, - lpBuffer + (*lpNumberOfBytesWritten), - nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); - + nbWritten = write(pComm->fd_write, + lpBuffer + (*lpNumberOfBytesWritten), + nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); + if (nbWritten < 0) { DEBUG_WARN("CommWriteFile failed after %lu bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); @@ -509,7 +509,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite return FALSE; } } - + *lpNumberOfBytesWritten += nbWritten; } @@ -530,5 +530,5 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite return TRUE; } - + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 28c5ae521..9ea0d949a 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -73,7 +73,7 @@ const char* _comm_serial_ioctl_name(ULONG number) static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, - LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; @@ -109,7 +109,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l DEBUG_MSG("CommDeviceIoControl: IoControlCode: 0x%0.8x", dwIoControlCode); - /* remoteSerialDriver to be use ... + /* remoteSerialDriver to be use ... * * FIXME: might prefer to use an automatic rather than static structure */ @@ -188,12 +188,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_properties) { COMMPROP *pProperties = (COMMPROP*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(COMMPROP)); if (nOutBufferSize < sizeof(COMMPROP)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_properties(pComm, pProperties)) @@ -226,12 +226,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_serial_chars) { SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(SERIAL_CHARS)); if (nOutBufferSize < sizeof(SERIAL_CHARS)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_serial_chars(pComm, pSerialChars)) @@ -264,12 +264,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_line_control) { SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL)); if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_line_control(pComm, pLineControl)) @@ -302,12 +302,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_handflow) { SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(SERIAL_HANDFLOW)); if (nOutBufferSize < sizeof(SERIAL_HANDFLOW)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_handflow(pComm, pHandflow)) @@ -340,12 +340,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_timeouts) { SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS)); if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_timeouts(pComm, pHandflow)) @@ -393,12 +393,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_modemstatus) { ULONG *pRegister = (ULONG*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(ULONG)); if (nOutBufferSize < sizeof(ULONG)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_modemstatus(pComm, pRegister)) @@ -431,12 +431,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_wait_mask) { ULONG *pWaitMask = (ULONG*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(ULONG)); if (nOutBufferSize < sizeof(ULONG)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_wait_mask(pComm, pWaitMask)) @@ -452,12 +452,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->wait_on_mask) { ULONG *pOutputMask = (ULONG*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(ULONG)); if (nOutBufferSize < sizeof(ULONG)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->wait_on_mask(pComm, pOutputMask)) @@ -510,12 +510,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_commstatus) { SERIAL_STATUS *pCommstatus = (SERIAL_STATUS*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(SERIAL_STATUS)); if (nOutBufferSize < sizeof(SERIAL_STATUS)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_commstatus(pComm, pCommstatus)) @@ -563,12 +563,12 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (pRemoteSerialDriver->get_dtrrts) { ULONG *pMask = (ULONG*)lpOutBuffer; - + assert(nOutBufferSize >= sizeof(ULONG)); if (nOutBufferSize < sizeof(ULONG)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return FALSE; } if (!pRemoteSerialDriver->get_dtrrts(pComm, pMask)) @@ -578,15 +578,15 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return TRUE; } break; - + } } - - DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), - dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name); + + DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; - + } @@ -603,7 +603,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l * ERROR_CALL_NOT_IMPLEMENTED unimplemented ioctl */ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, - LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; BOOL result; @@ -621,14 +621,14 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe } result = _CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, - lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); if (pComm->permissive) { if (!result) { DEBUG_WARN("[permissive]: whereas it failed, made to succeed IoControlCode=[0x%lX] %s, last-error: 0x%lX", - dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError()); + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError()); } return TRUE; /* always! */ diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 283e524b3..70e5ba556 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -37,22 +37,22 @@ * Ntddpar.h http://msdn.microsoft.com/en-us/cc308431.aspx */ -#ifdef __cplusplus -extern "C" { +#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 +#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 _SERIAL_BAUD_RATE @@ -90,51 +90,51 @@ typedef struct _SERIAL_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_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) +#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 _SERIAL_TIMEOUTS { - ULONG ReadIntervalTimeout; - ULONG ReadTotalTimeoutMultiplier; - ULONG ReadTotalTimeoutConstant; - ULONG WriteTotalTimeoutMultiplier; - ULONG WriteTotalTimeoutConstant; + ULONG ReadIntervalTimeout; + ULONG ReadTotalTimeoutMultiplier; + ULONG ReadTotalTimeoutConstant; + ULONG WriteTotalTimeoutMultiplier; + ULONG WriteTotalTimeoutConstant; } SERIAL_TIMEOUTS,*PSERIAL_TIMEOUTS; @@ -148,19 +148,19 @@ typedef struct _SERIAL_TIMEOUTS #define SERIAL_MSR_DCD 0x80 -#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_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 typedef struct _SERIAL_QUEUE_SIZE { @@ -169,41 +169,41 @@ typedef struct _SERIAL_QUEUE_SIZE } 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 +#define SERIAL_PURGE_TXABORT 0x00000001 +#define SERIAL_PURGE_RXABORT 0x00000002 +#define SERIAL_PURGE_TXCLEAR 0x00000004 +#define SERIAL_PURGE_RXCLEAR 0x00000008 typedef struct _SERIAL_STATUS -{ - ULONG Errors; - ULONG HoldReasons; - ULONG AmountInInQueue; - ULONG AmountInOutQueue; +{ + ULONG Errors; + ULONG HoldReasons; + ULONG AmountInInQueue; + ULONG AmountInOutQueue; BOOLEAN EofReceived; - BOOLEAN WaitForImmediate; -} SERIAL_STATUS, *PSERIAL_STATUS; + 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_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_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) +#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 NULL if not supported by the underlying remote driver. diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 2e16358a2..16c369076 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -56,12 +56,12 @@ static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars) /* 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 = +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_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | @@ -96,7 +96,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); - + /* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */ if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT)) @@ -120,8 +120,8 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) /* specific functions only */ -static REMOTE_SERIAL_DRIVER _SerCx2Sys = -{ +static REMOTE_SERIAL_DRIVER _SerCx2Sys = +{ .id = RemoteSerialDriverSerCx2Sys, .name = _T("SerCx2.sys"), .set_baud_rate = NULL, diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.h b/winpr/libwinpr/comm/comm_sercx2_sys.h index 2d4be7655..0707ab124 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.h +++ b/winpr/libwinpr/comm/comm_sercx2_sys.h @@ -24,13 +24,13 @@ #include "comm_ioctl.h" -#ifdef __cplusplus -extern "C" { +#ifdef __cplusplus +extern "C" { #endif REMOTE_SERIAL_DRIVER* SerCx2Sys_s(); -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 11c0e4d5e..6f6d1f6c9 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -177,7 +177,7 @@ static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) { if (_SERCX_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate) { - newSpeed = _SERCX_SYS_BAUD_TABLE[i][0]; + newSpeed = _SERCX_SYS_BAUD_TABLE[i][0]; if (cfsetspeed(&futureState, newSpeed) < 0) { DEBUG_WARN("failed to set speed 0x%x (%lu)", newSpeed, pBaudRate->BaudRate); @@ -239,7 +239,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW)); - /* filter out unsupported bits by SerCx.sys + /* filter out unsupported bits by SerCx.sys * * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx */ @@ -303,7 +303,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) SetLastError(ERROR_CALL_NOT_IMPLEMENTED); result = FALSE; } - + if (!pSerialSys->set_handflow(pComm, &SerCxHandflow)) return FALSE; @@ -318,7 +318,7 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) result = pSerialSys->get_handflow(pComm, pHandflow); - /* filter out unsupported bits by SerCx.sys + /* filter out unsupported bits by SerCx.sys * * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx */ @@ -331,12 +331,12 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ -static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK = +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_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | @@ -369,7 +369,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) /* specific functions only */ -static REMOTE_SERIAL_DRIVER _SerCxSys = +static REMOTE_SERIAL_DRIVER _SerCxSys = { .id = RemoteSerialDriverSerCxSys, .name = _T("SerCx.sys"), diff --git a/winpr/libwinpr/comm/comm_sercx_sys.h b/winpr/libwinpr/comm/comm_sercx_sys.h index d66c546ee..e54392060 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.h +++ b/winpr/libwinpr/comm/comm_sercx_sys.h @@ -24,13 +24,13 @@ #include "comm_ioctl.h" -#ifdef __cplusplus -extern "C" { +#ifdef __cplusplus +extern "C" { #endif REMOTE_SERIAL_DRIVER* SerCxSys_s(); -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index d83d0cfae..1790c76ac 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -44,7 +44,7 @@ /* * Linux, Windows speeds - * + * */ static const speed_t _SERIAL_SYS_BAUD_TABLE[][2] = { #ifdef B0 @@ -105,47 +105,8 @@ static const speed_t _SERIAL_SYS_BAUD_TABLE[][2] = { #ifdef B115200 {B115200, SERIAL_BAUD_115200}, /* _SERIAL_MAX_BAUD */ #endif -/* undefined by serial.sys: -#ifdef B230400 - {B230400, }, -#endif -#ifdef B460800 - {B460800, }, -#endif -#ifdef B500000 - {B500000, }, -#endif -#ifdef B576000 - {B576000, }, -#endif -#ifdef B921600 - {B921600, }, -#endif -#ifdef B1000000 - {B1000000, }, -#endif -#ifdef B1152000 - {B1152000, }, -#endif -#ifdef B1500000 - {B1500000, }, -#endif -#ifdef B2000000 - {B2000000, }, -#endif -#ifdef B2500000 - {B2500000, }, -#endif -#ifdef B3000000 - {B3000000, }, -#endif -#ifdef B3500000 - {B3500000, }, -#endif -#ifdef B4000000 - {B4000000, }, __MAX_BAUD -#endif -*/ + + /* no greater speed defined by serial.sys */ }; #define _SERIAL_MAX_BAUD B115200 @@ -185,7 +146,7 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) pProperties->dwProvSubType = PST_UNSPECIFIED; /* TMP: TODO: to be finalized */ - pProperties->dwProvCapabilities = + pProperties->dwProvCapabilities = /*PCF_16BITMODE | PCF_DTRDSR |*/ PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD | */ PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS | PCF_TOTALTIMEOUTS |*/ PCF_XONXOFF; @@ -330,7 +291,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar /* According the Linux's n_tty discipline, charaters with a * parity error can only be let unchanged, replaced by \0 or - * get the prefix the prefix \377 \0 + * get the prefix the prefix \377 \0 */ /* FIXME: see also: _set_handflow() */ @@ -384,13 +345,13 @@ static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars) } ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS)); - + /* EofChar unsupported */ /* ErrorChar unsupported */ /* BreakChar unsupported */ - + /* TMP: FIXME: see also: _set_serial_chars() */ /* EventChar */ @@ -436,7 +397,7 @@ static BOOL _set_line_control(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLin case STOP_BITS_1_5: DEBUG_WARN("Unsupported one and a half stop bits."); break; - + case STOP_BITS_2: upcomingTermios.c_cflag |= CSTOPB; break; @@ -445,7 +406,7 @@ static BOOL _set_line_control(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLin DEBUG_WARN("unexpected number of stop bits: %d\n", pLineControl->StopBits); result = FALSE; /* but keep on */ break; - } + } switch (pLineControl->Parity) @@ -580,11 +541,11 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) /* logical XOR */ if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || - ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) + ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) { DEBUG_WARN("SERIAL_DTR_CONTROL:%s and SERIAL_RTS_CONTROL:%s cannot be different, HUPCL will be set since it is claimed for one of the both lines.", - (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) ? "ON" : "OFF", - (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) ? "ON" : "OFF"); + (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) ? "ON" : "OFF", + (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) ? "ON" : "OFF"); } if ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) || (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) @@ -604,11 +565,11 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) /* logical XOR */ if ((!(pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) || - ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && !(pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE))) + ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && !(pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE))) { DEBUG_WARN("SERIAL_CTS_HANDSHAKE:%s and SERIAL_RTS_HANDSHAKE:%s cannot be different, CRTSCTS will be set since it is claimed for one of the both lines.", - (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) ? "ON" : "OFF", - (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) ? "ON" : "OFF"); + (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) ? "ON" : "OFF", + (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) ? "ON" : "OFF"); } if ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) || (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) @@ -724,13 +685,13 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) } /* XonLimit */ - + // FIXME: could be implemented during read/write I/O if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE) { DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %lu", pHandflow->XonLimit); SetLastError(ERROR_NOT_SUPPORTED); - result = FALSE; /* but keep on */ + result = FALSE; /* but keep on */ } /* XoffChar */ @@ -740,7 +701,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) { DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %lu", pHandflow->XoffLimit); SetLastError(ERROR_NOT_SUPPORTED); - result = FALSE; /* but keep on */ + result = FALSE; /* but keep on */ } @@ -774,7 +735,7 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL; /* SERIAL_DTR_HANDSHAKE unsupported */ - + if (currentTermios.c_cflag & CRTSCTS) pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE; @@ -782,7 +743,7 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) /* SERIAL_DCD_HANDSHAKE unsupported */ - /* SERIAL_DSR_SENSITIVITY unsupported */ + /* SERIAL_DSR_SENSITIVITY unsupported */ /* SERIAL_ERROR_ABORT unsupported */ @@ -964,7 +925,7 @@ static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) } ZeroMemory(pRegister, sizeof(ULONG)); - + /* FIXME: Is the last read of the MSR register available or * cached somewhere? Not quite sure we need to return the 4 * LSBits anyway. A direct access to the register -- which @@ -990,12 +951,12 @@ static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) } /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ -static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK = +static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK = SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | - SERIAL_EV_DSR | + SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | @@ -1113,7 +1074,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - + /* FIXME: currently relying too much on the fact the server * sends a single IRP_MJ_WRITE or IRP_MJ_READ at a time * (taking care though that one IRP_MJ_WRITE and one @@ -1144,7 +1105,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); } - + assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */ } } @@ -1152,7 +1113,7 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) { /* Purges the transmit buffer, if one exists. */ - + if (tcflush(pComm->fd, TCOFLUSH) < 0) { DEBUG_WARN("tcflush(TCOFLUSH) failure, errno=[%d] %s", errno, strerror(errno)); @@ -1185,7 +1146,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) { /* http://msdn.microsoft.com/en-us/library/jj673022%28v=vs.85%29.aspx */ - struct serial_icounter_struct currentCounters; + struct serial_icounter_struct currentCounters; /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); @@ -1238,7 +1199,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) /* HoldReasons */ - + /* TODO: SERIAL_TX_WAITING_FOR_CTS */ /* TODO: SERIAL_TX_WAITING_FOR_DSR */ @@ -1280,7 +1241,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) /* BOOLEAN WaitForImmediate; TMP: TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR supported */ - + /* other events based on counters */ @@ -1290,7 +1251,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) } if ((currentCounters.tx != pComm->counters.tx) && /* at least a transmission occurred AND ...*/ - (pCommstatus->AmountInOutQueue == 0)) /* output bufer is now empty */ + (pCommstatus->AmountInOutQueue == 0)) /* output bufer is now empty */ { pComm->PendingEvents |= SERIAL_EV_TXEMPTY; } @@ -1386,7 +1347,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) /* NB: ensure to leave the critical section before to return */ EnterCriticalSection(&pComm->EventsLock); - + if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) { pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; @@ -1460,7 +1421,7 @@ static BOOL _set_break_on(WINPR_COMM *pComm) return TRUE; } - + static BOOL _set_break_off(WINPR_COMM *pComm) { @@ -1512,17 +1473,17 @@ BOOL _get_dtrrts(WINPR_COMM *pComm, ULONG *pMask) } *pMask = 0; - + if (!(lines & TIOCM_DTR)) *pMask |= SERIAL_DTR_STATE; if (!(lines & TIOCM_RTS)) *pMask |= SERIAL_RTS_STATE; - + return TRUE; } -static REMOTE_SERIAL_DRIVER _SerialSys = +static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, .name = _T("Serial.sys"), diff --git a/winpr/libwinpr/comm/comm_serial_sys.h b/winpr/libwinpr/comm/comm_serial_sys.h index ec5f7847f..6858437b3 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.h +++ b/winpr/libwinpr/comm/comm_serial_sys.h @@ -24,13 +24,13 @@ #include "comm_ioctl.h" -#ifdef __cplusplus -extern "C" { +#ifdef __cplusplus +extern "C" { #endif REMOTE_SERIAL_DRIVER* SerialSys_s(); -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/winpr/libwinpr/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c index b5e212ab6..edb48bd93 100644 --- a/winpr/libwinpr/comm/test/TestCommConfig.c +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -33,8 +33,8 @@ int TestCommConfig(int argc, char* argv[]) COMMPROP commProp; hComm = CreateFileA(lpFileName, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm && (hComm != INVALID_HANDLE_VALUE)) { @@ -51,12 +51,12 @@ int TestCommConfig(int argc, char* argv[]) } hComm = CreateFileA(lpFileName, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE, /* invalid parmaeter */ - NULL, - CREATE_NEW, /* invalid parameter */ - 0, - (HANDLE)1234); /* invalid parmaeter */ + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, /* invalid parmaeter */ + NULL, + CREATE_NEW, /* invalid parameter */ + 0, + (HANDLE)1234); /* invalid parmaeter */ if (hComm != INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFileA failure: could create a handle with some invalid parameters %s\n", lpFileName); @@ -65,8 +65,8 @@ int TestCommConfig(int argc, char* argv[]) hComm = CreateFileA(lpFileName, - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (!hComm || (hComm == INVALID_HANDLE_VALUE)) { @@ -139,4 +139,3 @@ int TestCommConfig(int argc, char* argv[]) return 0; } - diff --git a/winpr/libwinpr/comm/test/TestCommDevice.c b/winpr/libwinpr/comm/test/TestCommDevice.c index 4c1334728..a99424bd7 100644 --- a/winpr/libwinpr/comm/test/TestCommDevice.c +++ b/winpr/libwinpr/comm/test/TestCommDevice.c @@ -32,9 +32,9 @@ static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) 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")); + lpDeviceName, + (expectedResult ? "TRUE" : "FALSE"), + (result ? "TRUE" : "FALSE")); return FALSE; } @@ -43,9 +43,9 @@ static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) 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")); + lpDeviceName, + (expectedResult ? "TRUE" : "FALSE"), + (result ? "TRUE" : "FALSE")); return FALSE; } @@ -61,8 +61,8 @@ static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) if (_tcscmp(_T("/dev/test"), lpTargetPath) != 0) { - _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"), - lpDeviceName, _T("/dev/test"), lpTargetPath); + _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"), + lpDeviceName, _T("/dev/test"), lpTargetPath); return FALSE; } @@ -77,8 +77,8 @@ static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) { if (tcslen > 0) { - _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: , result: %d %s\n"), - lpDeviceName, tcslen, lpTargetPath); + _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: , result: %d %s\n"), + lpDeviceName, tcslen, lpTargetPath); return FALSE; } diff --git a/winpr/libwinpr/comm/test/TestControlSettings.c b/winpr/libwinpr/comm/test/TestControlSettings.c index 15963da30..dde4c982c 100644 --- a/winpr/libwinpr/comm/test/TestControlSettings.c +++ b/winpr/libwinpr/comm/test/TestControlSettings.c @@ -39,15 +39,15 @@ int TestControlSettings(int argc, char* argv[]) } hComm = CreateFile("COM1", - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); return EXIT_FAILURE; } - + ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); @@ -55,7 +55,7 @@ int TestControlSettings(int argc, char* argv[]) { fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); return FALSE; - } + } /* Test 1 */ @@ -67,7 +67,7 @@ int TestControlSettings(int argc, char* argv[]) { fprintf(stderr, "SetCommState failure; GetLastError(): %0.8x\n", GetLastError()); return FALSE; - } + } ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); @@ -75,13 +75,13 @@ int TestControlSettings(int argc, char* argv[]) { fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); return FALSE; - } + } if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY)) { fprintf(stderr, "test1 failed.\n"); return FALSE; - } + } /* Test 2 */ @@ -94,7 +94,7 @@ int TestControlSettings(int argc, char* argv[]) { fprintf(stderr, "SetCommState failure; GetLastError(): %0.8x\n", GetLastError()); return FALSE; - } + } ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); @@ -102,13 +102,13 @@ int TestControlSettings(int argc, char* argv[]) { fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); return FALSE; - } + } if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY)) { fprintf(stderr, "test2 failed.\n"); return FALSE; - } + } if (!CloseHandle(hComm)) diff --git a/winpr/libwinpr/comm/test/TestGetCommState.c b/winpr/libwinpr/comm/test/TestGetCommState.c index ab2d1f441..c6a2747e9 100644 --- a/winpr/libwinpr/comm/test/TestGetCommState.c +++ b/winpr/libwinpr/comm/test/TestGetCommState.c @@ -55,7 +55,7 @@ static BOOL test_generic(HANDLE hComm) printf("GetCommState failure: Ox%x, with adjusted DCBlength\n", GetLastError()); return FALSE; } - + pDcb = (DCB*)calloc(1, sizeof(DCB) * 2); pDcb->DCBlength = sizeof(DCB) * 2; result = GetCommState(hComm, pDcb); @@ -84,8 +84,8 @@ int TestGetCommState(int argc, char* argv[]) } hComm = CreateFile("COM1", - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { printf("CreateFileA failure: 0x%x\n", GetLastError()); diff --git a/winpr/libwinpr/comm/test/TestHandflow.c b/winpr/libwinpr/comm/test/TestHandflow.c index 6f1286d00..471e5488e 100644 --- a/winpr/libwinpr/comm/test/TestHandflow.c +++ b/winpr/libwinpr/comm/test/TestHandflow.c @@ -46,8 +46,8 @@ int TestHandflow(int argc, char* argv[]) } hComm = CreateFile("COM1", - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); diff --git a/winpr/libwinpr/comm/test/TestSerialChars.c b/winpr/libwinpr/comm/test/TestSerialChars.c index 7ca879ea4..1a8f65332 100644 --- a/winpr/libwinpr/comm/test/TestSerialChars.c +++ b/winpr/libwinpr/comm/test/TestSerialChars.c @@ -46,7 +46,7 @@ static BOOL test_SerCxSys(HANDLE hComm) { fprintf(stderr, "GetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError()); return FALSE; - } + } if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0')) { @@ -115,7 +115,7 @@ static BOOL test_SerCx2Sys(HANDLE hComm) { fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError()); return FALSE; - } + } if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') || (dcb.XonChar != '\0') || (dcb.XoffChar != '\0')) { @@ -140,8 +140,8 @@ int TestSerialChars(int argc, char* argv[]) } hComm = CreateFile("COM1", - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c index 0ddfb89fe..a152dd197 100644 --- a/winpr/libwinpr/comm/test/TestSetCommState.c +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -269,7 +269,7 @@ static BOOL test_generic(HANDLE hComm) { DCB dcb, dcb2; BOOL result; - + init_empty_dcb(&dcb); result = GetCommState(hComm, &dcb); if (!result) @@ -329,8 +329,8 @@ int TestSetCommState(int argc, char* argv[]) } hComm = CreateFile("COM1", - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); diff --git a/winpr/libwinpr/comm/test/TestTimeouts.c b/winpr/libwinpr/comm/test/TestTimeouts.c index 4799eb794..3045f486d 100644 --- a/winpr/libwinpr/comm/test/TestTimeouts.c +++ b/winpr/libwinpr/comm/test/TestTimeouts.c @@ -87,8 +87,8 @@ int TestTimeouts(int argc, char* argv[]) } hComm = CreateFile("COM1", - GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); if (hComm == INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); From 34c3654faf55b5e54e3b58a95898bdbda49d1373 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 17 Jun 2014 15:19:16 +0200 Subject: [PATCH 51/61] winpr-comm: implemented IOCTL_SERIAL_CONFIG_SIZE --- winpr/include/winpr/comm.h | 4 ++-- winpr/libwinpr/comm/comm_ioctl.c | 22 ++++++++++++++++++++++ winpr/libwinpr/comm/comm_ioctl.h | 1 + winpr/libwinpr/comm/comm_sercx2_sys.c | 1 + winpr/libwinpr/comm/comm_sercx_sys.c | 1 + winpr/libwinpr/comm/comm_serial_sys.c | 9 +++++++++ 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 9e5d67357..bbbe78f86 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -441,7 +441,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 /* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ /* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ -/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */ +#define IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 /* IOCTL_SERIAL_GET_STATS 0x001B008C */ /* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ /* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ @@ -504,7 +504,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"}, // {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"}, // {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"}, - // {IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"}, + {IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"}, // {IOCTL_SERIAL_GET_STATS, "IOCTL_SERIAL_GET_STATS"}, // {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"}, // {IOCTL_SERIAL_GET_MODEM_CONTROL,"IOCTL_SERIAL_GET_MODEM_CONTROL"}, diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 9ea0d949a..736110945 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -580,6 +580,28 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l break; } + case IOCTL_SERIAL_CONFIG_SIZE: + { + if (pRemoteSerialDriver->config_size) + { + ULONG *pSize = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pRemoteSerialDriver->config_size(pComm, pSize)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 70e5ba556..ad0628245 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -241,6 +241,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 16c369076..5b685bd87 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -151,6 +151,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .set_xoff = NULL, /* not supported by SerCx2.sys */ .set_xon = NULL, /* not supported by SerCx2.sys */ .get_dtrrts = NULL, + .config_size = NULL, /* not supported by SerCx2.sys */ }; diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 6f6d1f6c9..2ba21e6c1 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -400,6 +400,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .set_xoff = NULL, .set_xon = NULL, .get_dtrrts = NULL, + .config_size = NULL, /* not supported by SerCx.sys */ }; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 1790c76ac..2621ce1f3 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1483,6 +1483,14 @@ BOOL _get_dtrrts(WINPR_COMM *pComm, ULONG *pMask) } +BOOL _config_size(WINPR_COMM *pComm, ULONG *pSize) +{ + /* http://msdn.microsoft.com/en-us/library/ff546548%28v=vs.85%29.aspx */ + pSize = 0; + return TRUE; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1514,6 +1522,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_xoff = _set_xoff, .set_xon = _set_xon, .get_dtrrts = _get_dtrrts, + .config_size = _config_size, }; From 9fc0e6eccc5bff549a7a8f9a352445ffb617b130 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 17 Jun 2014 16:34:20 +0200 Subject: [PATCH 52/61] winpr-comm: CommReadFile and CommWriteFile are now protected by a mutex winpr-comm: implemented IOCTL_SERIAL_IMMEDIATE_CHAR --- channels/serial/client/serial_main.c | 1 + winpr/include/winpr/comm.h | 4 +- winpr/libwinpr/comm/comm.c | 5 ++ winpr/libwinpr/comm/comm.h | 2 + winpr/libwinpr/comm/comm_io.c | 75 ++++++++++++++++----------- winpr/libwinpr/comm/comm_ioctl.c | 17 ++++++ winpr/libwinpr/comm/comm_ioctl.h | 1 + winpr/libwinpr/comm/comm_sercx2_sys.c | 1 + winpr/libwinpr/comm/comm_sercx_sys.c | 3 ++ winpr/libwinpr/comm/comm_serial_sys.c | 16 ++++++ winpr/libwinpr/handle/handle.c | 2 + 11 files changed, 96 insertions(+), 31 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 0d0d9a2dc..5b99996a6 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -774,6 +774,7 @@ static void serial_irp_request(DEVICE* device, IRP* irp) MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); } + static void serial_free(DEVICE* device) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index bbbe78f86..3b1e34b92 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -428,7 +428,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 #define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 #define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 -/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ +#define IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 #define IOCTL_SERIAL_PURGE 0x001B004C #define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 #define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 @@ -494,7 +494,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"}, {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, {IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"}, - // {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, + {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"}, {IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"}, {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index cbff32d55..0fe1ba1ef 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1140,6 +1140,8 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } + InitializeCriticalSection(&pComm->ReadLock); + pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK); if (pComm->fd_write < 0) { @@ -1156,6 +1158,9 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } + InitializeCriticalSection(&pComm->WriteLock); + + /* TMP: TODO: FIXME: this information is at least needed for * get/set baud functions. Is it possible to pull this * information? Could be a command line argument. diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 950ef19a1..5cfb3f2d2 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -50,9 +50,11 @@ struct winpr_comm 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). * diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index bfce8d3e5..53fe67135 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -95,48 +95,50 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, struct timeval tmaxTimeout, *pTmaxTimeout; struct termios currentTermios; + EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */ + if (hDevice == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (lpOverlapped != NULL) { SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; + goto return_false; } if (lpNumberOfBytesRead == NULL) { SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ - return FALSE; + goto return_false; } *lpNumberOfBytesRead = 0; /* will be ajusted if required ... */ if (nNumberOfBytesToRead <= 0) /* N */ { - return TRUE; /* FIXME: or FALSE? */ + goto return_true; /* FIXME: or FALSE? */ } if (tcgetattr(pComm->fd, ¤tTermios) < 0) { SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } if (currentTermios.c_lflag & ICANON) { DEBUG_WARN("Canonical mode not supported"); /* the timeout could not be set */ SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; + goto return_false; } /* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx @@ -162,7 +164,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { DEBUG_WARN("ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG"); SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + goto return_false; } /* VMIN */ @@ -214,7 +216,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { DEBUG_WARN("CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } } @@ -252,7 +254,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } if (nbFds == 0) @@ -260,7 +262,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* timeout */ SetLastError(ERROR_TIMEOUT); - return FALSE; + goto return_false; } @@ -280,7 +282,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, else { DEBUG_WARN("unexpected error on reading fd_read_event, errno=[%d] %s\n", errno, strerror(errno)); - /* FIXME: return FALSE ? */ + /* FIXME: goto return_false ? */ } assert(errno == EAGAIN); @@ -289,7 +291,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (event == FREERDP_PURGE_RXABORT) { SetLastError(ERROR_CANCELLED); - return FALSE; + goto return_false; } assert(event == FREERDP_PURGE_RXABORT); /* no other expected event so far */ @@ -310,18 +312,18 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (errno == EAGAIN) { /* keep on */ - return TRUE; /* expect a read-loop to be implemented on the server side */ + 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 */ - return FALSE; + goto return_false; } else { assert(FALSE); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } } @@ -329,16 +331,23 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { /* termios timeout */ SetLastError(ERROR_TIMEOUT); - return FALSE; + goto return_false; } *lpNumberOfBytesRead = nbRead; - return TRUE; + goto return_true; } assert(FALSE); *lpNumberOfBytesRead = 0; + + return_false: + LeaveCriticalSection(&pComm->ReadLock); return FALSE; + + return_true: + LeaveCriticalSection(&pComm->ReadLock); + return TRUE; } @@ -355,35 +364,37 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite WINPR_COMM* pComm = (WINPR_COMM*) hDevice; struct timeval tmaxTimeout, *pTmaxTimeout; + EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */ + if (hDevice == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (lpOverlapped != NULL) { SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; + goto return_false; } if (lpNumberOfBytesWritten == NULL) { SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ - return FALSE; + goto return_false; } *lpNumberOfBytesWritten = 0; /* will be ajusted if required ... */ if (nNumberOfBytesToWrite <= 0) { - return TRUE; /* FIXME: or FALSE? */ + goto return_true; /* FIXME: or FALSE? */ } /* FIXME: had expected eventfd_write() to return EAGAIN when @@ -434,7 +445,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } if (nbFds == 0) @@ -442,7 +453,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite /* timeout */ SetLastError(ERROR_TIMEOUT); - return FALSE; + goto return_false; } @@ -462,7 +473,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite else { DEBUG_WARN("unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno)); - /* FIXME: return FALSE ? */ + /* FIXME: goto return_false ? */ } assert(errno == EAGAIN); @@ -471,7 +482,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite if (event == FREERDP_PURGE_TXABORT) { SetLastError(ERROR_CANCELLED); - return FALSE; + goto return_false; } assert(event == FREERDP_PURGE_TXABORT); /* no other expected event so far */ @@ -500,13 +511,13 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite else if (errno == EBADF) { SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ - return FALSE; + goto return_false; } else { assert(FALSE); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } } @@ -527,7 +538,13 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite tcdrain(pComm->fd_write); + return_true: + LeaveCriticalSection(&pComm->WriteLock); return TRUE; + + return_false: + LeaveCriticalSection(&pComm->WriteLock); + return FALSE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 736110945..9c5985ea6 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -602,6 +602,23 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l break; } + case IOCTL_SERIAL_IMMEDIATE_CHAR: + { + if (pRemoteSerialDriver->immediate_char) + { + UCHAR *pChar = (UCHAR*)lpInBuffer; + + assert(nInBufferSize >= sizeof(UCHAR)); + if (nInBufferSize < sizeof(UCHAR)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pRemoteSerialDriver->immediate_char(pComm, pChar); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index ad0628245..c3c1ee244 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -242,6 +242,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 5b685bd87..0790cd7bf 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -152,6 +152,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .set_xon = NULL, /* not supported by SerCx2.sys */ .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx2.sys */ + .immediate_char = NULL, /* not supported by SerCx2.sys */ }; diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 2ba21e6c1..b86919ce1 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -401,6 +401,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .set_xon = NULL, .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx.sys */ + .immediate_char = NULL, }; @@ -445,6 +446,8 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.get_dtrrts = pSerialSys->get_dtrrts; + _SerCxSys.immediate_char = pSerialSys->immediate_char; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 2621ce1f3..632eddfb5 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1491,6 +1491,21 @@ BOOL _config_size(WINPR_COMM *pComm, ULONG *pSize) } +BOOL _immediate_char(WINPR_COMM *pComm, const UCHAR *pChar) +{ + BOOL result; + DWORD nbBytesWritten = -1; + + /* FIXME: CommWriteFile uses a critical section, shall it be interrupted? */ + + result = CommWriteFile(pComm, pChar, 1, &nbBytesWritten, NULL); + + assert(nbBytesWritten == 1); + + return result; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1523,6 +1538,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_xon = _set_xon, .get_dtrrts = _get_dtrrts, .config_size = _config_size, + .immediate_char = _immediate_char, }; diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index d2523e43e..0cee4b391 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -211,6 +211,8 @@ BOOL CloseHandle(HANDLE hObject) comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; LeaveCriticalSection(&comm->EventsLock); + DeleteCriticalSection(&comm->ReadLock); + DeleteCriticalSection(&comm->WriteLock); DeleteCriticalSection(&comm->EventsLock); if (comm->fd > 0) From ff9babed4e23a81bf821f6d439c78c7777c864a4 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 17 Jun 2014 17:18:42 +0200 Subject: [PATCH 53/61] serial: cleaned up serial_main and removed other files which have been replaced by winpr-comm --- channels/serial/client/serial_constants.h | 154 --- channels/serial/client/serial_main.c | 160 +-- channels/serial/client/serial_tty.c | 1079 --------------------- channels/serial/client/serial_tty.h | 80 -- 4 files changed, 49 insertions(+), 1424 deletions(-) delete mode 100644 channels/serial/client/serial_constants.h delete mode 100644 channels/serial/client/serial_tty.c delete mode 100644 channels/serial/client/serial_tty.h diff --git a/channels/serial/client/serial_constants.h b/channels/serial/client/serial_constants.h deleted file mode 100644 index a42c4f001..000000000 --- a/channels/serial/client/serial_constants.h +++ /dev/null @@ -1,154 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Serial Port Device Service Virtual Channel - * - * Copyright 2011 O.S. Systems Software Ltda. - * Copyright 2011 Eduardo Fiss Beloni - * - * 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 __SERIAL_CONSTANTS_H -#define __SERIAL_CONSTANTS_H - -/* http://www.codeproject.com/KB/system/chaiyasit_t.aspx */ -#define SERIAL_TIMEOUT_MAX 4294967295u - -/* DR_CONTROL_REQ.IoControlCode */ -enum DR_PORT_CONTROL_REQ -{ - IOCTL_SERIAL_SET_BAUD_RATE = 0x001B0004, - IOCTL_SERIAL_GET_BAUD_RATE = 0x001B0050, - IOCTL_SERIAL_SET_LINE_CONTROL = 0x001B000C, - IOCTL_SERIAL_GET_LINE_CONTROL = 0x001B0054, - IOCTL_SERIAL_SET_TIMEOUTS = 0x001B001C, - IOCTL_SERIAL_GET_TIMEOUTS = 0x001B0020, - -/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ - IOCTL_SERIAL_GET_CHARS = 0x001B0058, - IOCTL_SERIAL_SET_CHARS = 0x001B005C, - - IOCTL_SERIAL_SET_DTR = 0x001B0024, - IOCTL_SERIAL_CLR_DTR = 0x001B0028, - IOCTL_SERIAL_RESET_DEVICE = 0x001B002C, - IOCTL_SERIAL_SET_RTS = 0x001B0030, - IOCTL_SERIAL_CLR_RTS = 0x001B0034, - IOCTL_SERIAL_SET_XOFF = 0x001B0038, - IOCTL_SERIAL_SET_XON = 0x001B003C, - IOCTL_SERIAL_SET_BREAK_ON = 0x001B0010, - IOCTL_SERIAL_SET_BREAK_OFF = 0x001B0014, - IOCTL_SERIAL_SET_QUEUE_SIZE = 0x001B0008, - IOCTL_SERIAL_GET_WAIT_MASK = 0x001B0040, - IOCTL_SERIAL_SET_WAIT_MASK = 0x001B0044, - IOCTL_SERIAL_WAIT_ON_MASK = 0x001B0048, - IOCTL_SERIAL_IMMEDIATE_CHAR = 0x001B0018, - IOCTL_SERIAL_PURGE = 0x001B004C, - IOCTL_SERIAL_GET_HANDFLOW = 0x001B0060, - IOCTL_SERIAL_SET_HANDFLOW = 0x001B0064, - IOCTL_SERIAL_GET_MODEMSTATUS = 0x001B0068, - IOCTL_SERIAL_GET_DTRRTS = 0x001B0078, - -/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */ - IOCTL_SERIAL_GET_COMMSTATUS = 0x001B006C, - - IOCTL_SERIAL_GET_PROPERTIES = 0x001B0074, - IOCTL_SERIAL_XOFF_COUNTER = 0x001B0070, - IOCTL_SERIAL_LSRMST_INSERT = 0x001B007C, - IOCTL_SERIAL_CONFIG_SIZE = 0x001B0080, - IOCTL_SERIAL_GET_STATS = 0x001B008C, - IOCTL_SERIAL_CLEAR_STATS = 0x001B0090, - IOCTL_SERIAL_GET_MODEM_CONTROL = 0x001B0094, - IOCTL_SERIAL_SET_MODEM_CONTROL = 0x001B0098, - IOCTL_SERIAL_SET_FIFO_CONTROL = 0x001B009C, -}; - -enum SERIAL_PURGE_MASK -{ - SERIAL_PURGE_TXABORT = 0x00000001, - SERIAL_PURGE_RXABORT = 0x00000002, - SERIAL_PURGE_TXCLEAR = 0x00000004, - SERIAL_PURGE_RXCLEAR = 0x00000008, -}; - -enum SERIAL_WAIT_MASK -{ - SERIAL_EV_RXCHAR = 0x0001, /* Any Character received */ - SERIAL_EV_RXFLAG = 0x0002, /* Received certain character */ - SERIAL_EV_TXEMPTY = 0x0004, /* Transmitt Queue Empty */ - SERIAL_EV_CTS = 0x0008, /* CTS changed state */ - SERIAL_EV_DSR = 0x0010, /* DSR changed state */ - SERIAL_EV_RLSD = 0x0020, /* RLSD changed state */ - SERIAL_EV_BREAK = 0x0040, /* BREAK received */ - SERIAL_EV_ERR = 0x0080, /* Line status error occurred */ - SERIAL_EV_RING = 0x0100, /* Ring signal detected */ - SERIAL_EV_PERR = 0x0200, /* Printer error occured */ - SERIAL_EV_RX80FULL = 0x0400,/* Receive buffer is 80 percent full */ - SERIAL_EV_EVENT1 = 0x0800, /* Provider specific event 1 */ - SERIAL_EV_EVENT2 = 0x1000, /* Provider specific event 2 */ -}; - -enum SERIAL_MODEM_STATUS -{ - SERIAL_MS_DTR = 0x01, - SERIAL_MS_RTS = 0x02, - SERIAL_MS_CTS = 0x10, - SERIAL_MS_DSR = 0x20, - SERIAL_MS_RNG = 0x40, - SERIAL_MS_CAR = 0x80, -}; - -enum SERIAL_HANDFLOW -{ - SERIAL_DTR_CONTROL = 0x01, - SERIAL_CTS_HANDSHAKE = 0x08, - SERIAL_ERROR_ABORT = 0x80000000, -}; - -enum SERIAL_FLOW_CONTROL -{ - SERIAL_XON_HANDSHAKE = 0x01, - SERIAL_XOFF_HANDSHAKE = 0x02, - SERIAL_DSR_SENSITIVITY = 0x40, -}; - -enum SERIAL_CHARS -{ - SERIAL_CHAR_EOF = 0, - SERIAL_CHAR_ERROR = 1, - SERIAL_CHAR_BREAK = 2, - SERIAL_CHAR_EVENT = 3, - SERIAL_CHAR_XON = 4, - SERIAL_CHAR_XOFF = 5, -}; - -enum SERIAL_ABORT_IO -{ - SERIAL_ABORT_IO_NONE = 0, - SERIAL_ABORT_IO_WRITE = 1, - SERIAL_ABORT_IO_READ = 2, -}; - -enum SERIAL_STOP_BITS -{ - SERIAL_STOP_BITS_1 = 0, - SERIAL_STOP_BITS_2 = 2, -}; - -enum SERIAL_PARITY -{ - SERIAL_NO_PARITY = 0, - SERIAL_ODD_PARITY = 1, - SERIAL_EVEN_PARITY = 2, -}; - -#endif diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 5b99996a6..0e6d078a5 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -87,6 +87,51 @@ struct _IRP_THREAD_DATA IRP *irp; }; +static UINT32 _GetLastErrorToIoStatus() +{ + /* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */ + + switch(GetLastError()) + { + case ERROR_BAD_DEVICE: + return STATUS_INVALID_DEVICE_REQUEST; + + case ERROR_CALL_NOT_IMPLEMENTED: + return STATUS_NOT_IMPLEMENTED; + + case ERROR_CANCELLED: + return STATUS_CANCELLED; + + case ERROR_INSUFFICIENT_BUFFER: + return STATUS_BUFFER_TOO_SMALL; /* NB: STATUS_BUFFER_SIZE_TOO_SMALL not defined */ + + case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */ + return STATUS_INVALID_DEVICE_STATE; + + case ERROR_INVALID_HANDLE: + return STATUS_INVALID_DEVICE_REQUEST; + + case ERROR_INVALID_PARAMETER: + return STATUS_INVALID_PARAMETER; + + case ERROR_IO_DEVICE: + return STATUS_IO_DEVICE_ERROR; + + case ERROR_IO_PENDING: + return STATUS_PENDING; + + case ERROR_NOT_SUPPORTED: + return STATUS_NOT_SUPPORTED; + + case ERROR_TIMEOUT: + return STATUS_TIMEOUT; + + /* no default */ + } + + DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + return STATUS_UNSUCCESSFUL; +} static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { @@ -231,41 +276,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) { DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8X", serial->device.name, nbRead, GetLastError()); - switch(GetLastError()) - { - case ERROR_INVALID_HANDLE: - irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; - break; - - case ERROR_NOT_SUPPORTED: - irp->IoStatus = STATUS_NOT_SUPPORTED; - break; - - case ERROR_INVALID_PARAMETER: - irp->IoStatus = STATUS_INVALID_PARAMETER; - break; - - case ERROR_IO_DEVICE: - irp->IoStatus = STATUS_IO_DEVICE_ERROR; - break; - - case ERROR_TIMEOUT: - irp->IoStatus = STATUS_TIMEOUT; - break; - - case ERROR_BAD_DEVICE: - irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; - break; - - case ERROR_CANCELLED: - irp->IoStatus = STATUS_CANCELLED; - break; - - default: - DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); - irp->IoStatus = STATUS_UNSUCCESSFUL; - break; - } + irp->IoStatus = _GetLastErrorToIoStatus(); } DEBUG_SVC("%lu bytes read from %s", nbRead, serial->device.name); @@ -311,41 +322,8 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) else { DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8X", serial->device.name, nbWritten, GetLastError()); - switch(GetLastError()) - { - case ERROR_INVALID_HANDLE: - irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; - break; - case ERROR_NOT_SUPPORTED: - irp->IoStatus = STATUS_NOT_SUPPORTED; - break; - - case ERROR_INVALID_PARAMETER: - irp->IoStatus = STATUS_INVALID_PARAMETER; - break; - - case ERROR_IO_DEVICE: - irp->IoStatus = STATUS_IO_DEVICE_ERROR; - break; - - case ERROR_TIMEOUT: - irp->IoStatus = STATUS_TIMEOUT; - break; - - case ERROR_BAD_DEVICE: - irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; - break; - - case ERROR_CANCELLED: - irp->IoStatus = STATUS_CANCELLED; - break; - - default: - DEBUG_SVC("unexpected last-error: 0x%X", GetLastError()); - irp->IoStatus = STATUS_UNSUCCESSFUL; - break; - } + irp->IoStatus = _GetLastErrorToIoStatus(); } DEBUG_SVC("%lu bytes written to %s", nbWritten, serial->device.name); @@ -399,47 +377,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%X", IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); - // TMP: TODO: Status codes to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests - - switch(GetLastError()) - { - case ERROR_INVALID_HANDLE: - irp->IoStatus = STATUS_INVALID_DEVICE_REQUEST; - break; - - case ERROR_NOT_SUPPORTED: - irp->IoStatus = STATUS_NOT_SUPPORTED; - break; - - case ERROR_INSUFFICIENT_BUFFER: - irp->IoStatus = STATUS_BUFFER_TOO_SMALL; /* TMP: better have STATUS_BUFFER_SIZE_TOO_SMALL? http://msdn.microsoft.com/en-us/library/windows/hardware/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */ - break; - - case ERROR_INVALID_PARAMETER: - irp->IoStatus = STATUS_INVALID_PARAMETER; - break; - - case ERROR_CALL_NOT_IMPLEMENTED: - irp->IoStatus = STATUS_NOT_IMPLEMENTED; - break; - - case ERROR_IO_PENDING: - irp->IoStatus = STATUS_PENDING; - break; - - case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */ - irp->IoStatus = STATUS_INVALID_DEVICE_STATE; - break; - - case ERROR_CANCELLED: - irp->IoStatus = STATUS_CANCELLED; - break; - - default: - DEBUG_SVC("unexpected last-error: 0x%X", GetLastError()); - irp->IoStatus = STATUS_UNSUCCESSFUL; - break; - } + irp->IoStatus = _GetLastErrorToIoStatus(); } error_handle: @@ -605,7 +543,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) * CompletionId or the server sent again an IRP already posted * which didn't get yet a response (this later server behavior * at least observed with IOCTL_SERIAL_WAIT_ON_MASK and - * mstsc.exe. + * mstsc.exe). * * FIXME: behavior documented somewhere? behavior not yet * observed with FreeRDP). diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c deleted file mode 100644 index b1c1a92b6..000000000 --- a/channels/serial/client/serial_tty.c +++ /dev/null @@ -1,1079 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Serial Port Device Service Virtual Channel - * - * Copyright 2011 O.S. Systems Software Ltda. - * Copyright 2011 Eduardo Fiss Beloni - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#include -#include -#include -#endif - -#include -#include -#include -#include - -#include "serial_tty.h" -#include "serial_constants.h" - -#ifdef HAVE_SYS_MODEM_H -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include -#endif -#ifdef HAVE_SYS_STRTIO_H -#include -#endif - -#ifndef CRTSCTS -#define CRTSCTS 0 -#endif - -/* FIONREAD should really do the same thing as TIOCINQ, where it is not available */ - -#if !defined(TIOCINQ) && defined(FIONREAD) -#define TIOCINQ FIONREAD -#endif - -#if !defined(TIOCOUTQ) && defined(FIONWRITE) -#define TIOCOUTQ FIONWRITE -#endif - -/** - * Refer to ReactOS's ntddser.h (public domain) for constant definitions - */ - -static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len); -static void tty_set_termios(SERIAL_TTY* tty); -static BOOL tty_get_termios(SERIAL_TTY* tty); -static int tty_get_error_status(); - -UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abortIo) -{ - UINT32 result; - BYTE immediate; - int purge_mask; - UINT32 modemstate; - UINT32 begPos, endPos; - UINT32 OutputBufferLength; - UINT32 status = STATUS_SUCCESS; - UINT32 IoCtlDeviceType; - UINT32 IoCtlFunction; - UINT32 IoCtlMethod; - UINT32 IoCtlAccess; - - IoCtlMethod = (IoControlCode & 0x3); - IoCtlFunction = ((IoControlCode >> 2) & 0xFFF); - IoCtlAccess = ((IoControlCode >> 14) & 0x3); - IoCtlDeviceType = ((IoControlCode >> 16) & 0xFFFF); - - - /** - * FILE_DEVICE_SERIAL_PORT 0x0000001B - * FILE_DEVICE_UNKNOWN 0x00000022 - */ - - if (IoCtlDeviceType == 0x00000022) // TMP: !? - { - IoControlCode &= 0xFFFF; - IoControlCode |= (0x0000001B << 16); - } - - Stream_Seek_UINT32(output); /* OutputBufferLength (4 bytes) */ - begPos = (UINT32) Stream_GetPosition(output); - - switch (IoControlCode) - { - case IOCTL_SERIAL_SET_BAUD_RATE: - Stream_Read_UINT32(input, tty->baud_rate); - tty_set_termios(tty); - DEBUG_SVC("SERIAL_SET_BAUD_RATE %d", tty->baud_rate); - break; - - case IOCTL_SERIAL_GET_BAUD_RATE: - OutputBufferLength = 4; - Stream_Write_UINT32(output, tty->baud_rate); - DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate); - break; - - case IOCTL_SERIAL_SET_QUEUE_SIZE: - Stream_Read_UINT32(input, tty->queue_in_size); - Stream_Read_UINT32(input, tty->queue_out_size); - DEBUG_SVC("SERIAL_SET_QUEUE_SIZE in %d out %d", tty->queue_in_size, tty->queue_out_size); - break; - - case IOCTL_SERIAL_SET_LINE_CONTROL: - Stream_Read_UINT8(input, tty->stop_bits); - Stream_Read_UINT8(input, tty->parity); - Stream_Read_UINT8(input, tty->word_length); - tty_set_termios(tty); - DEBUG_SVC("SERIAL_SET_LINE_CONTROL stop %d parity %d word %d", - tty->stop_bits, tty->parity, tty->word_length); - break; - - case IOCTL_SERIAL_GET_LINE_CONTROL: - DEBUG_SVC("SERIAL_GET_LINE_CONTROL"); - OutputBufferLength = 3; - Stream_Write_UINT8(output, tty->stop_bits); - Stream_Write_UINT8(output, tty->parity); - Stream_Write_UINT8(output, tty->word_length); - break; - - case IOCTL_SERIAL_IMMEDIATE_CHAR: - DEBUG_SVC("SERIAL_IMMEDIATE_CHAR"); - Stream_Read_UINT8(input, immediate); - tty_write_data(tty, &immediate, 1); - break; - - case IOCTL_SERIAL_CONFIG_SIZE: - DEBUG_SVC("SERIAL_CONFIG_SIZE"); - OutputBufferLength = 4; - Stream_Write_UINT32(output, 0); - break; - - case IOCTL_SERIAL_GET_CHARS: - DEBUG_SVC("SERIAL_GET_CHARS"); - OutputBufferLength = 6; - Stream_Write(output, tty->chars, 6); - break; - - case IOCTL_SERIAL_SET_CHARS: - DEBUG_SVC("SERIAL_SET_CHARS"); - Stream_Read(input, tty->chars, 6); - tty_set_termios(tty); - break; - - case IOCTL_SERIAL_GET_HANDFLOW: - OutputBufferLength = 16; - tty_get_termios(tty); - Stream_Write_UINT32(output, tty->control); - Stream_Write_UINT32(output, tty->xonoff); - Stream_Write_UINT32(output, tty->onlimit); - Stream_Write_UINT32(output, tty->offlimit); - DEBUG_SVC("IOCTL_SERIAL_GET_HANDFLOW %X %X %X %X", - tty->control, tty->xonoff, tty->onlimit, tty->offlimit); - break; - - case IOCTL_SERIAL_SET_HANDFLOW: - Stream_Read_UINT32(input, tty->control); - Stream_Read_UINT32(input, tty->xonoff); - Stream_Read_UINT32(input, tty->onlimit); - Stream_Read_UINT32(input, tty->offlimit); - DEBUG_SVC("IOCTL_SERIAL_SET_HANDFLOW %X %X %X %X", - tty->control, tty->xonoff, tty->onlimit, tty->offlimit); - tty_set_termios(tty); - break; - - case IOCTL_SERIAL_SET_TIMEOUTS: - Stream_Read_UINT32(input, tty->read_interval_timeout); - Stream_Read_UINT32(input, tty->read_total_timeout_multiplier); - Stream_Read_UINT32(input, tty->read_total_timeout_constant); - Stream_Read_UINT32(input, tty->write_total_timeout_multiplier); - Stream_Read_UINT32(input, tty->write_total_timeout_constant); - - /* http://www.codeproject.com/KB/system/chaiyasit_t.aspx, see 'ReadIntervalTimeout' section - http://msdn.microsoft.com/en-us/library/ms885171.aspx */ - if (tty->read_interval_timeout == SERIAL_TIMEOUT_MAX) - { - tty->read_interval_timeout = 0; - tty->read_total_timeout_multiplier = 0; - } - - DEBUG_SVC("SERIAL_SET_TIMEOUTS read timeout %d %d %d", - tty->read_interval_timeout, - tty->read_total_timeout_multiplier, - tty->read_total_timeout_constant); - break; - - case IOCTL_SERIAL_GET_TIMEOUTS: - DEBUG_SVC("SERIAL_GET_TIMEOUTS read timeout %d %d %d", - tty->read_interval_timeout, - tty->read_total_timeout_multiplier, - tty->read_total_timeout_constant); - OutputBufferLength = 20; - Stream_Write_UINT32(output, tty->read_interval_timeout); - Stream_Write_UINT32(output, tty->read_total_timeout_multiplier); - Stream_Write_UINT32(output, tty->read_total_timeout_constant); - Stream_Write_UINT32(output, tty->write_total_timeout_multiplier); - Stream_Write_UINT32(output, tty->write_total_timeout_constant); - break; - - case IOCTL_SERIAL_GET_WAIT_MASK: - DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask); - OutputBufferLength = 4; - Stream_Write_UINT32(output, tty->wait_mask); - break; - - case IOCTL_SERIAL_SET_WAIT_MASK: - Stream_Read_UINT32(input, tty->wait_mask); - DEBUG_SVC("SERIAL_SET_WAIT_MASK %X", tty->wait_mask); - break; - - case IOCTL_SERIAL_SET_DTR: - DEBUG_SVC("SERIAL_SET_DTR"); - ioctl(tty->fd, TIOCMGET, &result); - result |= TIOCM_DTR; - ioctl(tty->fd, TIOCMSET, &result); - tty->dtr = 1; - break; - - case IOCTL_SERIAL_CLR_DTR: - DEBUG_SVC("SERIAL_CLR_DTR"); - ioctl(tty->fd, TIOCMGET, &result); - result &= ~TIOCM_DTR; - ioctl(tty->fd, TIOCMSET, &result); - tty->dtr = 0; - break; - - case IOCTL_SERIAL_SET_RTS: - DEBUG_SVC("SERIAL_SET_RTS"); - ioctl(tty->fd, TIOCMGET, &result); - result |= TIOCM_RTS; - ioctl(tty->fd, TIOCMSET, &result); - tty->rts = 1; - break; - - case IOCTL_SERIAL_CLR_RTS: - DEBUG_SVC("SERIAL_CLR_RTS"); - ioctl(tty->fd, TIOCMGET, &result); - result &= ~TIOCM_RTS; - ioctl(tty->fd, TIOCMSET, &result); - tty->rts = 0; - break; - - case IOCTL_SERIAL_GET_MODEMSTATUS: - modemstate = 0; -#ifdef TIOCMGET - ioctl(tty->fd, TIOCMGET, &result); - if (result & TIOCM_CTS) - modemstate |= SERIAL_MS_CTS; - if (result & TIOCM_DSR) - modemstate |= SERIAL_MS_DSR; - if (result & TIOCM_RNG) - modemstate |= SERIAL_MS_RNG; - if (result & TIOCM_CAR) - modemstate |= SERIAL_MS_CAR; - if (result & TIOCM_DTR) - modemstate |= SERIAL_MS_DTR; - if (result & TIOCM_RTS) - modemstate |= SERIAL_MS_RTS; -#endif - DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate); - OutputBufferLength = 4; - Stream_Write_UINT32(output, modemstate); - break; - - case IOCTL_SERIAL_GET_COMMSTATUS: - OutputBufferLength = 18; - Stream_Write_UINT32(output, 0); /* Errors */ - Stream_Write_UINT32(output, 0); /* Hold reasons */ - - result = 0; -#ifdef TIOCINQ - ioctl(tty->fd, TIOCINQ, &result); -#endif - Stream_Write_UINT32(output, result); /* Amount in in queue */ - if (result) - DEBUG_SVC("SERIAL_GET_COMMSTATUS in queue %d", result); - - result = 0; -#ifdef TIOCOUTQ - ioctl(tty->fd, TIOCOUTQ, &result); -#endif - Stream_Write_UINT32(output, result); /* Amount in out queue */ - DEBUG_SVC("SERIAL_GET_COMMSTATUS out queue %d", result); - - Stream_Write_UINT8(output, 0); /* EofReceived */ - Stream_Write_UINT8(output, 0); /* WaitForImmediate */ - break; - - case IOCTL_SERIAL_PURGE: - Stream_Read_UINT32(input, purge_mask); - DEBUG_SVC("SERIAL_PURGE purge_mask %X", purge_mask); - - /* See http://msdn.microsoft.com/en-us/library/ms901431.aspx - PURGE_TXCLEAR Clears the output buffer, if the driver has one. - PURGE_RXCLEAR Clears the input buffer, if the driver has one. - - It clearly states to clear the *driver* buffer, not the port buffer - */ - -#ifdef DEBUG_SVC - if (purge_mask & SERIAL_PURGE_TXCLEAR) - DEBUG_SVC("Ignoring SERIAL_PURGE_TXCLEAR"); - if (purge_mask & SERIAL_PURGE_RXCLEAR) - DEBUG_SVC("Ignoring SERIAL_PURGE_RXCLEAR"); -#endif - - if (purge_mask & SERIAL_PURGE_TXABORT) - *abortIo |= SERIAL_ABORT_IO_WRITE; - if (purge_mask & SERIAL_PURGE_RXABORT) - *abortIo |= SERIAL_ABORT_IO_READ; - break; - case IOCTL_SERIAL_WAIT_ON_MASK: - DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask); - tty->event_pending = 1; - OutputBufferLength = 4; - if (serial_tty_get_event(tty, &result)) - { - DEBUG_SVC("WAIT end event = %X", result); - Stream_Write_UINT32(output, result); - break; - } - status = STATUS_PENDING; - break; - - case IOCTL_SERIAL_SET_BREAK_ON: - DEBUG_SVC("SERIAL_SET_BREAK_ON"); - tcsendbreak(tty->fd, 0); - break; - - case IOCTL_SERIAL_RESET_DEVICE: - DEBUG_SVC("SERIAL_RESET_DEVICE"); - break; - - case IOCTL_SERIAL_SET_BREAK_OFF: - DEBUG_SVC("SERIAL_SET_BREAK_OFF"); - break; - - case IOCTL_SERIAL_SET_XOFF: - DEBUG_SVC("SERIAL_SET_XOFF"); - break; - - case IOCTL_SERIAL_SET_XON: - DEBUG_SVC("SERIAL_SET_XON"); - tcflow(tty->fd, TCION); - break; - - default: - DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL 0x%08X", IoControlCode); - return STATUS_INVALID_PARAMETER; - } - - endPos = (UINT32) Stream_GetPosition(output); - OutputBufferLength = endPos - begPos; - - if (OutputBufferLength < 1) - { - Stream_Write_UINT8(output, 0); /* Padding (1 byte) */ - endPos = (UINT32) Stream_GetPosition(output); - OutputBufferLength = endPos - begPos; - } - - Stream_SealLength(output); - - Stream_SetPosition(output, 16); - Stream_Write_UINT32(output, OutputBufferLength); /* OutputBufferLength (4 bytes) */ - Stream_SetPosition(output, endPos); - - return status; -} - -BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length) -{ - ssize_t status; - long timeout = 90; - - /* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout - with requested read size */ - if (tty->read_total_timeout_multiplier | tty->read_total_timeout_constant) - { - timeout = - (tty->read_total_timeout_multiplier * (*Length) + - tty->read_total_timeout_constant + 99) / 100; - } - else if (tty->read_interval_timeout) - { - timeout = (tty->read_interval_timeout * (*Length) + 99) / 100; - } - - if (tty->timeout != timeout) - { - struct termios* ptermios; - - ptermios = (struct termios*) calloc(1, sizeof(struct termios)); - - if (tcgetattr(tty->fd, ptermios) < 0) - return FALSE; - - /** - * If a timeout is set, do a blocking read, which times out after some time. - * It will make FreeRDP less responsive, but it will improve serial performance, - * by not reading one character at a time. - */ - - if (timeout == 0) - { - ptermios->c_cc[VTIME] = 0; - ptermios->c_cc[VMIN] = 0; - } - else - { - ptermios->c_cc[VTIME] = timeout; - ptermios->c_cc[VMIN] = 1; - } - - tcsetattr(tty->fd, TCSANOW, ptermios); - tty->timeout = timeout; - } - - ZeroMemory(buffer, *Length); - - status = read(tty->fd, buffer, *Length); - - if (status < 0) - { - DEBUG_WARN("failed with %zd, errno=[%d] %s\n", - status, errno, strerror(errno)); - return FALSE; - } - - tty->event_txempty = status; - *Length = status; - - return TRUE; -} - -int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length) -{ - ssize_t status = 0; - UINT32 event_txempty = Length; - - while (Length > 0) - { - status = write(tty->fd, buffer, Length); - - if (status < 0) - { - if (errno == EAGAIN) - status = 0; - else - return status; - } - - Length -= status; - buffer += status; - } - - tty->event_txempty = event_txempty; - - return status; -} - -/** - * This function is used to deallocated a SERIAL_TTY structure. - * - * @param tty [in] - pointer to the SERIAL_TTY structure to deallocate. - * This will typically be allocated by a call to serial_tty_new(). - * On return, this pointer is invalid. - */ -void serial_tty_free(SERIAL_TTY* tty) -{ - // TMP: TBR - - if (!tty) - return; - - if (tty->fd >= 0) - { - if (tty->pold_termios) - tcsetattr(tty->fd, TCSANOW, tty->pold_termios); - - close(tty->fd); - } - - free(tty->ptermios); - free(tty->pold_termios); - free(tty); -} - -SERIAL_TTY* serial_tty_new(const char* path, UINT32 id) -{ - SERIAL_TTY* tty; - - tty = (SERIAL_TTY*) calloc(1, sizeof(SERIAL_TTY)); - - if (!tty) - return NULL; - - tty->id = id; - tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); - - if (tty->fd < 0) - { - perror("open"); - DEBUG_WARN("failed to open device %s", path); - serial_tty_free(tty); - return NULL; - } - else - { - DEBUG_SVC("tty fd %d successfully opened", tty->fd); - } - - tty->ptermios = (struct termios*) calloc(1, sizeof(struct termios)); - - if (!tty->ptermios) - { - serial_tty_free(tty); - return NULL; - } - - tty->pold_termios = (struct termios*) calloc(1, sizeof(struct termios)); - - if (!tty->pold_termios) - { - serial_tty_free(tty); - return NULL; - } - tcgetattr(tty->fd, tty->pold_termios); - - if (!tty_get_termios(tty)) - { - DEBUG_WARN("%s access denied", path); - fflush(stdout); - serial_tty_free(tty); - return NULL; - } - - tty->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - tty->ptermios->c_oflag &= ~OPOST; - tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tty->ptermios->c_cflag &= ~(CSIZE | PARENB); - tty->ptermios->c_cflag |= CS8; - - tty->ptermios->c_iflag = IGNPAR; - tty->ptermios->c_cflag |= CLOCAL | CREAD; - - tcsetattr(tty->fd, TCSANOW, tty->ptermios); - - tty->event_txempty = 0; - tty->event_cts = 0; - tty->event_dsr = 0; - tty->event_rlsd = 0; - tty->event_pending = 0; - - /* all read and writes should be non-blocking */ - if (fcntl(tty->fd, F_SETFL, O_NONBLOCK) == -1) - { - DEBUG_WARN("%s fcntl", path); - perror("fcntl"); - serial_tty_free(tty) ; - return NULL; - } - - tty->read_total_timeout_constant = 5; - - return tty; -} - -BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result) -{ - int bytes; - BOOL status = FALSE; - - *result = 0; - -#ifdef TIOCINQ - /* When wait_mask is set to zero we ought to cancel it all - For reference: http://msdn.microsoft.com/en-us/library/aa910487.aspx */ - if (tty->wait_mask == 0) - { - tty->event_pending = 0; - return TRUE; - } - - ioctl(tty->fd, TIOCINQ, &bytes); - - if (bytes > 0) - { - DEBUG_SVC("bytes %d", bytes); - - if (bytes > tty->event_rlsd) - { - tty->event_rlsd = bytes; - - if (tty->wait_mask & SERIAL_EV_RLSD) - { - DEBUG_SVC("SERIAL_EV_RLSD"); - *result |= SERIAL_EV_RLSD; - status = TRUE; - } - } - - if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG)) - { - DEBUG_SVC("SERIAL_EV_RXFLAG bytes %d", bytes); - *result |= SERIAL_EV_RXFLAG; - status = TRUE; - } - - if ((tty->wait_mask & SERIAL_EV_RXCHAR)) - { - DEBUG_SVC("SERIAL_EV_RXCHAR bytes %d", bytes); - *result |= SERIAL_EV_RXCHAR; - status = TRUE; - } - } - else - { - tty->event_rlsd = 0; - } -#endif - -#ifdef TIOCOUTQ - ioctl(tty->fd, TIOCOUTQ, &bytes); - if ((bytes == 0) && (tty->event_txempty > 0) && (tty->wait_mask & SERIAL_EV_TXEMPTY)) - { - DEBUG_SVC("SERIAL_EV_TXEMPTY"); - *result |= SERIAL_EV_TXEMPTY; - status = TRUE; - } - tty->event_txempty = bytes; -#endif - - ioctl(tty->fd, TIOCMGET, &bytes); - if ((bytes & TIOCM_DSR) != tty->event_dsr) - { - tty->event_dsr = bytes & TIOCM_DSR; - if (tty->wait_mask & SERIAL_EV_DSR) - { - DEBUG_SVC("SERIAL_EV_DSR %s", (bytes & TIOCM_DSR) ? "ON" : "OFF"); - *result |= SERIAL_EV_DSR; - status = TRUE; - } - } - - if ((bytes & TIOCM_CTS) != tty->event_cts) - { - tty->event_cts = bytes & TIOCM_CTS; - if (tty->wait_mask & SERIAL_EV_CTS) - { - DEBUG_SVC("SERIAL_EV_CTS %s", (bytes & TIOCM_CTS) ? "ON" : "OFF"); - *result |= SERIAL_EV_CTS; - status = TRUE; - } - } - - if (status) - tty->event_pending = 0; - - return status; -} - -static BOOL tty_get_termios(SERIAL_TTY* tty) -{ - speed_t speed; - struct termios* ptermios; - ptermios = tty->ptermios; - - DEBUG_SVC("tcgetattr? %d", tcgetattr(tty->fd, ptermios) >= 0); - - if (tcgetattr(tty->fd, ptermios) < 0) - return FALSE; - - speed = cfgetispeed(ptermios); - - switch (speed) - { -#ifdef B75 - case B75: - tty->baud_rate = 75; - break; -#endif -#ifdef B110 - case B110: - tty->baud_rate = 110; - break; -#endif -#ifdef B134 - case B134: - tty->baud_rate = 134; - break; -#endif -#ifdef B150 - case B150: - tty->baud_rate = 150; - break; -#endif -#ifdef B300 - case B300: - tty->baud_rate = 300; - break; -#endif -#ifdef B600 - case B600: - tty->baud_rate = 600; - break; -#endif -#ifdef B1200 - case B1200: - tty->baud_rate = 1200; - break; -#endif -#ifdef B1800 - case B1800: - tty->baud_rate = 1800; - break; -#endif -#ifdef B2400 - case B2400: - tty->baud_rate = 2400; - break; -#endif -#ifdef B4800 - case B4800: - tty->baud_rate = 4800; - break; -#endif -#ifdef B9600 - case B9600: - tty->baud_rate = 9600; - break; -#endif -#ifdef B19200 - case B19200: - tty->baud_rate = 19200; - break; -#endif -#ifdef B38400 - case B38400: - tty->baud_rate = 38400; - break; -#endif -#ifdef B57600 - case B57600: - tty->baud_rate = 57600; - break; -#endif -#ifdef B115200 - case B115200: - tty->baud_rate = 115200; - break; -#endif -#ifdef B230400 - case B230400: - tty->baud_rate = 230400; - break; -#endif -#ifdef B460800 - case B460800: - tty->baud_rate = 460800; - break; -#endif - default: - tty->baud_rate = 9600; - break; - } - - speed = cfgetospeed(ptermios); - tty->dtr = (speed == B0) ? 0 : 1; - - tty->stop_bits = (ptermios->c_cflag & CSTOPB) ? SERIAL_STOP_BITS_2 : SERIAL_STOP_BITS_1; - tty->parity = - (ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? SERIAL_ODD_PARITY : - SERIAL_EVEN_PARITY) : SERIAL_NO_PARITY; - switch (ptermios->c_cflag & CSIZE) - { - case CS5: - tty->word_length = 5; - break; - case CS6: - tty->word_length = 6; - break; - case CS7: - tty->word_length = 7; - break; - default: - tty->word_length = 8; - break; - } - - if (ptermios->c_cflag & CRTSCTS) - { - tty->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT; - } - else - { - tty->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT; - } - - tty->xonoff = SERIAL_DSR_SENSITIVITY; - - if (ptermios->c_iflag & IXON) - tty->xonoff |= SERIAL_XON_HANDSHAKE; - - if (ptermios->c_iflag & IXOFF) - tty->xonoff |= SERIAL_XOFF_HANDSHAKE; - - tty->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART]; - tty->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP]; - tty->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF]; - tty->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR]; - tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL]; - - tty->timeout = ptermios->c_cc[VTIME]; - - return TRUE; -} - -static void tty_set_termios(SERIAL_TTY* tty) -{ - speed_t speed; - struct termios* ptermios; - - ptermios = tty->ptermios; - - switch (tty->baud_rate) - { -#ifdef B75 - case 75: - speed = B75; - break; -#endif -#ifdef B110 - case 110: - speed = B110; - break; -#endif -#ifdef B134 - case 134: - speed = B134; - break; -#endif -#ifdef B150 - case 150: - speed = B150; - break; -#endif -#ifdef B300 - case 300: - speed = B300; - break; -#endif -#ifdef B600 - case 600: - speed = B600; - break; -#endif -#ifdef B1200 - case 1200: - speed = B1200; - break; -#endif -#ifdef B1800 - case 1800: - speed = B1800; - break; -#endif -#ifdef B2400 - case 2400: - speed = B2400; - break; -#endif -#ifdef B4800 - case 4800: - speed = B4800; - break; -#endif -#ifdef B9600 - case 9600: - speed = B9600; - break; -#endif -#ifdef B19200 - case 19200: - speed = B19200; - break; -#endif -#ifdef B38400 - case 38400: - speed = B38400; - break; -#endif -#ifdef B57600 - case 57600: - speed = B57600; - break; -#endif -#ifdef B115200 - case 115200: - speed = B115200; - break; -#endif -#ifdef B230400 - case 230400: - speed = B115200; - break; -#endif -#ifdef B460800 - case 460800: - speed = B115200; - break; -#endif - default: - speed = B9600; - break; - } - -#ifdef CBAUD - ptermios->c_cflag &= ~CBAUD; - ptermios->c_cflag |= speed; -#else - /* on systems with separate ispeed and ospeed, we can remember the speed - in ispeed while changing DTR with ospeed */ - cfsetispeed(tty->ptermios, speed); - cfsetospeed(tty->ptermios, tty->dtr ? speed : 0); -#endif - - ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS); - - switch (tty->stop_bits) - { - case SERIAL_STOP_BITS_2: - ptermios->c_cflag |= CSTOPB; - break; - - default: - ptermios->c_cflag &= ~CSTOPB; - break; - } - - switch (tty->parity) - { - case SERIAL_EVEN_PARITY: - ptermios->c_cflag |= PARENB; - break; - - case SERIAL_ODD_PARITY: - ptermios->c_cflag |= PARENB | PARODD; - break; - - case SERIAL_NO_PARITY: - ptermios->c_cflag &= ~(PARENB | PARODD); - break; - } - - switch (tty->word_length) - { - case 5: - ptermios->c_cflag |= CS5; - break; - case 6: - ptermios->c_cflag |= CS6; - break; - case 7: - ptermios->c_cflag |= CS7; - break; - default: - ptermios->c_cflag |= CS8; - break; - } - -#if 0 - if (tty->rts) - ptermios->c_cflag |= CRTSCTS; - else - ptermios->c_cflag &= ~CRTSCTS; -#endif - - if (tty->control & SERIAL_CTS_HANDSHAKE) - { - ptermios->c_cflag |= CRTSCTS; - } - else - { - ptermios->c_cflag &= ~CRTSCTS; - } - - - if (tty->xonoff & SERIAL_XON_HANDSHAKE) - { - ptermios->c_iflag |= IXON | IMAXBEL; - } - if (tty->xonoff & SERIAL_XOFF_HANDSHAKE) - { - ptermios->c_iflag |= IXOFF | IMAXBEL; - } - - if ((tty->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0) - { - ptermios->c_iflag &= ~IXON; - ptermios->c_iflag &= ~IXOFF; - } - - ptermios->c_cc[VSTART] = tty->chars[SERIAL_CHAR_XON]; - ptermios->c_cc[VSTOP] = tty->chars[SERIAL_CHAR_XOFF]; - ptermios->c_cc[VEOF] = tty->chars[SERIAL_CHAR_EOF]; - ptermios->c_cc[VINTR] = tty->chars[SERIAL_CHAR_BREAK]; - ptermios->c_cc[VKILL] = tty->chars[SERIAL_CHAR_ERROR]; - - tcsetattr(tty->fd, TCSANOW, ptermios); -} - -static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len) -{ - ssize_t status; - - status = write(tty->fd, data, len); - - if (status < 0) - return tty_get_error_status(); - - tty->event_txempty = status; - - return STATUS_SUCCESS; -} - -static int tty_get_error_status() -{ - switch (errno) - { - case EACCES: - case ENOTDIR: - case ENFILE: - return STATUS_ACCESS_DENIED; - case EISDIR: - return STATUS_FILE_IS_A_DIRECTORY; - case EEXIST: - return STATUS_OBJECT_NAME_COLLISION; - case EBADF: - return STATUS_INVALID_HANDLE; - default: - return STATUS_NO_SUCH_FILE; - } -} diff --git a/channels/serial/client/serial_tty.h b/channels/serial/client/serial_tty.h deleted file mode 100644 index 840c448ec..000000000 --- a/channels/serial/client/serial_tty.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Serial Port Device Service Virtual Channel - * - * Copyright 2011 O.S. Systems Software Ltda. - * Copyright 2011 Eduardo Fiss Beloni - * - * 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 __SERIAL_TTY_H -#define __SERIAL_TTY_H - -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include - -#include - -typedef struct _SERIAL_TTY SERIAL_TTY; - -struct _SERIAL_TTY -{ - UINT32 id; - int fd; - - int dtr; - int rts; - UINT32 control; - UINT32 xonoff; - UINT32 onlimit; - UINT32 offlimit; - UINT32 baud_rate; - UINT32 queue_in_size; - UINT32 queue_out_size; - UINT32 wait_mask; - UINT32 read_interval_timeout; - UINT32 read_total_timeout_multiplier; - UINT32 read_total_timeout_constant; - UINT32 write_total_timeout_multiplier; - UINT32 write_total_timeout_constant; - BYTE stop_bits; - BYTE parity; - BYTE word_length; - BYTE chars[6]; - struct termios* ptermios; - struct termios* pold_termios; - int event_txempty; - int event_cts; - int event_dsr; - int event_rlsd; - int event_pending; - long timeout; -}; - -SERIAL_TTY* serial_tty_new(const char* path, UINT32 id); -void serial_tty_free(SERIAL_TTY* tty); - -BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length); -int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length); -UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abort_io); - -BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result); - -#endif /* __SERIAL_TTY_H */ From 62d893b2bd656c407d51ed64835621501a315eaa Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Tue, 17 Jun 2014 17:49:06 +0200 Subject: [PATCH 54/61] winpr-comm: implemented IOCTL_SERIAL_RESET_DEVICE --- winpr/include/winpr/comm.h | 4 ++-- winpr/libwinpr/comm/comm_ioctl.c | 10 +++++++++- winpr/libwinpr/comm/comm_ioctl.h | 1 + winpr/libwinpr/comm/comm_sercx2_sys.c | 1 + winpr/libwinpr/comm/comm_sercx_sys.c | 1 + winpr/libwinpr/comm/comm_serial_sys.c | 7 +++++++ 6 files changed, 21 insertions(+), 3 deletions(-) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 3b1e34b92..55803741b 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -417,7 +417,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_SET_DTR 0x001B0024 #define IOCTL_SERIAL_CLR_DTR 0x001B0028 -/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */ +#define IOCTL_SERIAL_RESET_DEVICE 0x001B002C #define IOCTL_SERIAL_SET_RTS 0x001B0030 #define IOCTL_SERIAL_CLR_RTS 0x001B0034 #define IOCTL_SERIAL_SET_XOFF 0x001B0038 @@ -483,7 +483,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_SET_CHARS, "IOCTL_SERIAL_SET_CHARS"}, {IOCTL_SERIAL_SET_DTR, "IOCTL_SERIAL_SET_DTR"}, {IOCTL_SERIAL_CLR_DTR, "IOCTL_SERIAL_CLR_DTR"}, - // {IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"}, + {IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"}, {IOCTL_SERIAL_SET_RTS, "IOCTL_SERIAL_SET_RTS"}, {IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"}, {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"}, diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 9c5985ea6..7420020b7 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -619,11 +619,19 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } break; } + case IOCTL_SERIAL_RESET_DEVICE: + { + if (pRemoteSerialDriver->reset_device) + { + return pRemoteSerialDriver->reset_device(pComm); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */ return FALSE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index c3c1ee244..661963e58 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -243,6 +243,7 @@ typedef struct _REMOTE_SERIAL_DRIVER 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); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 0790cd7bf..e74df1205 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -153,6 +153,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx2.sys */ .immediate_char = NULL, /* not supported by SerCx2.sys */ + .reset_device = NULL, /* not supported by SerCx2.sys */ }; diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index b86919ce1..0a6e68392 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -402,6 +402,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx.sys */ .immediate_char = NULL, + .reset_device = NULL, /* not supported by SerCx.sys */ }; diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 632eddfb5..3fcf0ab1a 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1506,6 +1506,12 @@ BOOL _immediate_char(WINPR_COMM *pComm, const UCHAR *pChar) } +BOOL _reset_device(WINPR_COMM *pComm) +{ + /* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx */ + return TRUE; +} + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1539,6 +1545,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .get_dtrrts = _get_dtrrts, .config_size = _config_size, .immediate_char = _immediate_char, + .reset_device = _reset_device, }; From 62298fcd951226581dfdb9d00e01e89a52f49c52 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 18 Jun 2014 15:58:08 +0200 Subject: [PATCH 55/61] winpr-comm: renamed REMOTE_SERIAL_DRIVER by SERIAL_DRIVER or ServerSerialDriver according the context --- winpr/libwinpr/comm/comm.c | 8 +- winpr/libwinpr/comm/comm.h | 17 ++- winpr/libwinpr/comm/comm_ioctl.c | 146 ++++++++++---------- winpr/libwinpr/comm/comm_ioctl.h | 8 +- winpr/libwinpr/comm/comm_sercx2_sys.c | 14 +- winpr/libwinpr/comm/comm_sercx2_sys.h | 2 +- winpr/libwinpr/comm/comm_sercx_sys.c | 16 +-- winpr/libwinpr/comm/comm_sercx_sys.h | 2 +- winpr/libwinpr/comm/comm_serial_sys.c | 6 +- winpr/libwinpr/comm/comm_serial_sys.h | 2 +- winpr/libwinpr/comm/test/TestGetCommState.c | 14 +- winpr/libwinpr/comm/test/TestHandflow.c | 6 +- winpr/libwinpr/comm/test/TestSerialChars.c | 4 +- winpr/libwinpr/comm/test/TestSetCommState.c | 14 +- winpr/libwinpr/comm/test/TestTimeouts.c | 6 +- 15 files changed, 132 insertions(+), 133 deletions(-) diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 0fe1ba1ef..14829d1df 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -999,7 +999,7 @@ BOOL IsCommDevice(LPCTSTR lpDeviceName) /** * Sets */ -void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID driverId) +void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID driverId) { ULONG Type; PVOID Object; @@ -1007,12 +1007,12 @@ void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID driverId) if (!winpr_Handle_GetInfo(hComm, &Type, &Object)) { - DEBUG_WARN("_comm_setRemoteSerialDriver failure"); + DEBUG_WARN("_comm_setServerSerialDriver failure"); return; } pComm = (WINPR_COMM*)Object; - pComm->remoteSerialDriverId = driverId; + pComm->serverSerialDriverId = driverId; } @@ -1165,7 +1165,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare * get/set baud functions. Is it possible to pull this * information? Could be a command line argument. */ - pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; + pComm->serverSerialDriverId = SerialDriverUnknown; InitializeCriticalSection(&pComm->EventsLock); diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 5cfb3f2d2..84952f4fc 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -34,13 +34,13 @@ * IOCTLs table according the remote serial driver: * http://msdn.microsoft.com/en-us/library/windows/hardware/dn265347%28v=vs.85%29.aspx */ -typedef enum _REMOTE_SERIAL_DRIVER_ID +typedef enum _SERIAL_DRIVER_ID { - RemoteSerialDriverUnknown = 0, - RemoteSerialDriverSerialSys, - RemoteSerialDriverSerCxSys, - RemoteSerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */ -} REMOTE_SERIAL_DRIVER_ID; + SerialDriverUnknown = 0, + SerialDriverSerialSys, + SerialDriverSerCxSys, + SerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */ +} SERIAL_DRIVER_ID; struct winpr_comm { @@ -65,8 +65,7 @@ struct winpr_comm */ BOOL permissive; - // TMP: to be renamed serverSerialDriverId - REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; + SERIAL_DRIVER_ID serverSerialDriverId; COMMTIMEOUTS timeouts; @@ -80,7 +79,7 @@ struct winpr_comm typedef struct winpr_comm WINPR_COMM; -void _comm_setRemoteSerialDriver(HANDLE hComm, REMOTE_SERIAL_DRIVER_ID); +void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID); /* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ #define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit unused by SERIAL_EV_* */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 7420020b7..3770a6f7b 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -76,7 +76,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; - REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; + SERIAL_DRIVER* pServerSerialDriver = NULL; /* clear any previous last error */ SetLastError(ERROR_SUCCESS); @@ -113,28 +113,28 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l * * FIXME: might prefer to use an automatic rather than static structure */ - switch (pComm->remoteSerialDriverId) + switch (pComm->serverSerialDriverId) { - case RemoteSerialDriverSerialSys: - pRemoteSerialDriver = SerialSys_s(); + case SerialDriverSerialSys: + pServerSerialDriver = SerialSys_s(); break; - case RemoteSerialDriverSerCxSys: - pRemoteSerialDriver = SerCxSys_s(); + case SerialDriverSerCxSys: + pServerSerialDriver = SerCxSys_s(); break; - case RemoteSerialDriverSerCx2Sys: - pRemoteSerialDriver = SerCx2Sys_s(); + case SerialDriverSerCx2Sys: + pServerSerialDriver = SerCx2Sys_s(); break; - case RemoteSerialDriverUnknown: + case SerialDriverUnknown: default: - DEBUG_MSG("Unknown remote serial driver (%d), using SerCx2.sys", pComm->remoteSerialDriverId); - pRemoteSerialDriver = SerCx2Sys_s(); + DEBUG_MSG("Unknown remote serial driver (%d), using SerCx2.sys", pComm->serverSerialDriverId); + pServerSerialDriver = SerCx2Sys_s(); break; } - assert(pRemoteSerialDriver != NULL); + assert(pServerSerialDriver != NULL); switch (dwIoControlCode) { @@ -147,7 +147,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_BAUD_RATE: { - if (pRemoteSerialDriver->set_baud_rate) + if (pServerSerialDriver->set_baud_rate) { SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer; @@ -158,13 +158,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_baud_rate(pComm, pBaudRate); + return pServerSerialDriver->set_baud_rate(pComm, pBaudRate); } break; } case IOCTL_SERIAL_GET_BAUD_RATE: { - if (pRemoteSerialDriver->get_baud_rate) + if (pServerSerialDriver->get_baud_rate) { SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer; @@ -175,7 +175,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_baud_rate(pComm, pBaudRate)) + if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate)) return FALSE; *lpBytesReturned = sizeof(SERIAL_BAUD_RATE); @@ -185,7 +185,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_GET_PROPERTIES: { - if (pRemoteSerialDriver->get_properties) + if (pServerSerialDriver->get_properties) { COMMPROP *pProperties = (COMMPROP*)lpOutBuffer; @@ -196,7 +196,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_properties(pComm, pProperties)) + if (!pServerSerialDriver->get_properties(pComm, pProperties)) return FALSE; *lpBytesReturned = sizeof(COMMPROP); @@ -206,7 +206,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_CHARS: { - if (pRemoteSerialDriver->set_serial_chars) + if (pServerSerialDriver->set_serial_chars) { SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpInBuffer; @@ -217,13 +217,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_serial_chars(pComm, pSerialChars); + return pServerSerialDriver->set_serial_chars(pComm, pSerialChars); } break; } case IOCTL_SERIAL_GET_CHARS: { - if (pRemoteSerialDriver->get_serial_chars) + if (pServerSerialDriver->get_serial_chars) { SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpOutBuffer; @@ -234,7 +234,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_serial_chars(pComm, pSerialChars)) + if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars)) return FALSE; *lpBytesReturned = sizeof(SERIAL_CHARS); @@ -244,7 +244,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_LINE_CONTROL: { - if (pRemoteSerialDriver->set_line_control) + if (pServerSerialDriver->set_line_control) { SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer; @@ -255,13 +255,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_line_control(pComm, pLineControl); + return pServerSerialDriver->set_line_control(pComm, pLineControl); } break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { - if (pRemoteSerialDriver->get_line_control) + if (pServerSerialDriver->get_line_control) { SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer; @@ -272,7 +272,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_line_control(pComm, pLineControl)) + if (!pServerSerialDriver->get_line_control(pComm, pLineControl)) return FALSE; *lpBytesReturned = sizeof(SERIAL_LINE_CONTROL); @@ -282,7 +282,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_HANDFLOW: { - if (pRemoteSerialDriver->set_handflow) + if (pServerSerialDriver->set_handflow) { SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpInBuffer; @@ -293,13 +293,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_handflow(pComm, pHandflow); + return pServerSerialDriver->set_handflow(pComm, pHandflow); } break; } case IOCTL_SERIAL_GET_HANDFLOW: { - if (pRemoteSerialDriver->get_handflow) + if (pServerSerialDriver->get_handflow) { SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer; @@ -310,7 +310,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_handflow(pComm, pHandflow)) + if (!pServerSerialDriver->get_handflow(pComm, pHandflow)) return FALSE; *lpBytesReturned = sizeof(SERIAL_HANDFLOW); @@ -320,7 +320,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_TIMEOUTS: { - if (pRemoteSerialDriver->set_timeouts) + if (pServerSerialDriver->set_timeouts) { SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer; @@ -331,13 +331,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_timeouts(pComm, pHandflow); + return pServerSerialDriver->set_timeouts(pComm, pHandflow); } break; } case IOCTL_SERIAL_GET_TIMEOUTS: { - if (pRemoteSerialDriver->get_timeouts) + if (pServerSerialDriver->get_timeouts) { SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer; @@ -348,7 +348,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_timeouts(pComm, pHandflow)) + if (!pServerSerialDriver->get_timeouts(pComm, pHandflow)) return FALSE; *lpBytesReturned = sizeof(SERIAL_TIMEOUTS); @@ -358,39 +358,39 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_DTR: { - if (pRemoteSerialDriver->set_dtr) + if (pServerSerialDriver->set_dtr) { - return pRemoteSerialDriver->set_dtr(pComm); + return pServerSerialDriver->set_dtr(pComm); } break; } case IOCTL_SERIAL_CLR_DTR: { - if (pRemoteSerialDriver->clear_dtr) + if (pServerSerialDriver->clear_dtr) { - return pRemoteSerialDriver->clear_dtr(pComm); + return pServerSerialDriver->clear_dtr(pComm); } break; } case IOCTL_SERIAL_SET_RTS: { - if (pRemoteSerialDriver->set_rts) + if (pServerSerialDriver->set_rts) { - return pRemoteSerialDriver->set_rts(pComm); + return pServerSerialDriver->set_rts(pComm); } break; } case IOCTL_SERIAL_CLR_RTS: { - if (pRemoteSerialDriver->clear_rts) + if (pServerSerialDriver->clear_rts) { - return pRemoteSerialDriver->clear_rts(pComm); + return pServerSerialDriver->clear_rts(pComm); } break; } case IOCTL_SERIAL_GET_MODEMSTATUS: { - if (pRemoteSerialDriver->get_modemstatus) + if (pServerSerialDriver->get_modemstatus) { ULONG *pRegister = (ULONG*)lpOutBuffer; @@ -401,7 +401,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_modemstatus(pComm, pRegister)) + if (!pServerSerialDriver->get_modemstatus(pComm, pRegister)) return FALSE; *lpBytesReturned = sizeof(ULONG); @@ -411,7 +411,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_WAIT_MASK: { - if (pRemoteSerialDriver->set_wait_mask) + if (pServerSerialDriver->set_wait_mask) { ULONG *pWaitMask = (ULONG*)lpInBuffer; @@ -422,13 +422,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_wait_mask(pComm, pWaitMask); + return pServerSerialDriver->set_wait_mask(pComm, pWaitMask); } break; } case IOCTL_SERIAL_GET_WAIT_MASK: { - if (pRemoteSerialDriver->get_wait_mask) + if (pServerSerialDriver->get_wait_mask) { ULONG *pWaitMask = (ULONG*)lpOutBuffer; @@ -439,7 +439,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_wait_mask(pComm, pWaitMask)) + if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask)) return FALSE; *lpBytesReturned = sizeof(ULONG); @@ -449,7 +449,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_WAIT_ON_MASK: { - if (pRemoteSerialDriver->wait_on_mask) + if (pServerSerialDriver->wait_on_mask) { ULONG *pOutputMask = (ULONG*)lpOutBuffer; @@ -460,7 +460,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->wait_on_mask(pComm, pOutputMask)) + if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask)) { *lpBytesReturned = sizeof(ULONG); /* TMP: TODO: all lpBytesReturned values to be reviewed on error */ return FALSE; @@ -473,7 +473,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_QUEUE_SIZE: { - if (pRemoteSerialDriver->set_queue_size) + if (pServerSerialDriver->set_queue_size) { SERIAL_QUEUE_SIZE *pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer; @@ -484,13 +484,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->set_queue_size(pComm, pQueueSize); + return pServerSerialDriver->set_queue_size(pComm, pQueueSize); } break; } case IOCTL_SERIAL_PURGE: { - if (pRemoteSerialDriver->purge) + if (pServerSerialDriver->purge) { ULONG *pPurgeMask = (ULONG*)lpInBuffer; @@ -501,13 +501,13 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->purge(pComm, pPurgeMask); + return pServerSerialDriver->purge(pComm, pPurgeMask); } break; } case IOCTL_SERIAL_GET_COMMSTATUS: { - if (pRemoteSerialDriver->get_commstatus) + if (pServerSerialDriver->get_commstatus) { SERIAL_STATUS *pCommstatus = (SERIAL_STATUS*)lpOutBuffer; @@ -518,7 +518,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_commstatus(pComm, pCommstatus)) + if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus)) return FALSE; *lpBytesReturned = sizeof(SERIAL_STATUS); @@ -528,39 +528,39 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_SET_BREAK_ON: { - if (pRemoteSerialDriver->set_break_on) + if (pServerSerialDriver->set_break_on) { - return pRemoteSerialDriver->set_break_on(pComm); + return pServerSerialDriver->set_break_on(pComm); } break; } case IOCTL_SERIAL_SET_BREAK_OFF: { - if (pRemoteSerialDriver->set_break_off) + if (pServerSerialDriver->set_break_off) { - return pRemoteSerialDriver->set_break_off(pComm); + return pServerSerialDriver->set_break_off(pComm); } break; } case IOCTL_SERIAL_SET_XOFF: { - if (pRemoteSerialDriver->set_xoff) + if (pServerSerialDriver->set_xoff) { - return pRemoteSerialDriver->set_xoff(pComm); + return pServerSerialDriver->set_xoff(pComm); } break; } case IOCTL_SERIAL_SET_XON: { - if (pRemoteSerialDriver->set_xon) + if (pServerSerialDriver->set_xon) { - return pRemoteSerialDriver->set_xon(pComm); + return pServerSerialDriver->set_xon(pComm); } break; } case IOCTL_SERIAL_GET_DTRRTS: { - if (pRemoteSerialDriver->get_dtrrts) + if (pServerSerialDriver->get_dtrrts) { ULONG *pMask = (ULONG*)lpOutBuffer; @@ -571,7 +571,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->get_dtrrts(pComm, pMask)) + if (!pServerSerialDriver->get_dtrrts(pComm, pMask)) return FALSE; *lpBytesReturned = sizeof(ULONG); @@ -582,7 +582,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_CONFIG_SIZE: { - if (pRemoteSerialDriver->config_size) + if (pServerSerialDriver->config_size) { ULONG *pSize = (ULONG*)lpOutBuffer; @@ -593,7 +593,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - if (!pRemoteSerialDriver->config_size(pComm, pSize)) + if (!pServerSerialDriver->config_size(pComm, pSize)) return FALSE; *lpBytesReturned = sizeof(ULONG); @@ -604,7 +604,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l } case IOCTL_SERIAL_IMMEDIATE_CHAR: { - if (pRemoteSerialDriver->immediate_char) + if (pServerSerialDriver->immediate_char) { UCHAR *pChar = (UCHAR*)lpInBuffer; @@ -615,22 +615,22 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l return FALSE; } - return pRemoteSerialDriver->immediate_char(pComm, pChar); + return pServerSerialDriver->immediate_char(pComm, pChar); } break; } case IOCTL_SERIAL_RESET_DEVICE: { - if (pRemoteSerialDriver->reset_device) + if (pServerSerialDriver->reset_device) { - return pRemoteSerialDriver->reset_device(pComm); + return pServerSerialDriver->reset_device(pComm); } break; } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), - dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name); + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */ return FALSE; diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 661963e58..99ada3154 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -206,13 +206,13 @@ typedef struct _SERIAL_STATUS #define SERIAL_DCD_STATE ((ULONG)0x00000080) /** - * A function might be NULL if not supported by the underlying remote driver. + * A function might be NULL if not supported by the underlying driver. * * FIXME: better have to use input and output buffers for all functions? */ -typedef struct _REMOTE_SERIAL_DRIVER +typedef struct _SERIAL_DRIVER { - REMOTE_SERIAL_DRIVER_ID id; + 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); @@ -245,7 +245,7 @@ typedef struct _REMOTE_SERIAL_DRIVER BOOL (*immediate_char)(WINPR_COMM *pComm, const UCHAR *pChar); BOOL (*reset_device)(WINPR_COMM *pComm); -} REMOTE_SERIAL_DRIVER; +} SERIAL_DRIVER; int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p); diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index e74df1205..9d09e8c98 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -75,7 +75,7 @@ static const ULONG _SERCX2_SYS_SUPPORTED_EV_MASK = static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) { ULONG possibleMask; - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); possibleMask = *pWaitMask & _SERCX2_SYS_SUPPORTED_EV_MASK; @@ -95,7 +95,7 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) { - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); /* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */ @@ -120,9 +120,9 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) /* specific functions only */ -static REMOTE_SERIAL_DRIVER _SerCx2Sys = +static SERIAL_DRIVER _SerCx2Sys = { - .id = RemoteSerialDriverSerCx2Sys, + .id = SerialDriverSerCx2Sys, .name = _T("SerCx2.sys"), .set_baud_rate = NULL, .get_baud_rate = NULL, @@ -157,11 +157,11 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = }; -REMOTE_SERIAL_DRIVER* SerCx2Sys_s() +SERIAL_DRIVER* SerCx2Sys_s() { /* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */ - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); - REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); _SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate; _SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.h b/winpr/libwinpr/comm/comm_sercx2_sys.h index 0707ab124..a37df299a 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.h +++ b/winpr/libwinpr/comm/comm_sercx2_sys.h @@ -28,7 +28,7 @@ extern "C" { #endif -REMOTE_SERIAL_DRIVER* SerCx2Sys_s(); +SERIAL_DRIVER* SerCx2Sys_s(); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 0a6e68392..db5faeb60 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -139,7 +139,7 @@ static const speed_t _SERCX_SYS_BAUD_TABLE[][3] = { static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) { int i; - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); if (!pSerialSys->get_properties(pComm, pProperties)) { @@ -235,7 +235,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) { SERIAL_HANDFLOW SerCxHandflow; BOOL result = TRUE; - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW)); @@ -314,7 +314,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) { BOOL result; - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); result = pSerialSys->get_handflow(pComm, pHandflow); @@ -350,7 +350,7 @@ static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK = static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) { ULONG possibleMask; - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK; @@ -369,9 +369,9 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) /* specific functions only */ -static REMOTE_SERIAL_DRIVER _SerCxSys = +static SERIAL_DRIVER _SerCxSys = { - .id = RemoteSerialDriverSerCxSys, + .id = SerialDriverSerCxSys, .name = _T("SerCx.sys"), .set_baud_rate = _set_baud_rate, .get_baud_rate = _get_baud_rate, @@ -407,10 +407,10 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = -REMOTE_SERIAL_DRIVER* SerCxSys_s() +SERIAL_DRIVER* SerCxSys_s() { /* _SerCxSys completed with inherited functions from SerialSys */ - REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerialSys = SerialSys_s(); _SerCxSys.set_serial_chars = pSerialSys->set_serial_chars; _SerCxSys.get_serial_chars = pSerialSys->get_serial_chars; diff --git a/winpr/libwinpr/comm/comm_sercx_sys.h b/winpr/libwinpr/comm/comm_sercx_sys.h index e54392060..a232f4b9e 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.h +++ b/winpr/libwinpr/comm/comm_sercx_sys.h @@ -28,7 +28,7 @@ extern "C" { #endif -REMOTE_SERIAL_DRIVER* SerCxSys_s(); +SERIAL_DRIVER* SerCxSys_s(); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 3fcf0ab1a..aafce8a61 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1512,9 +1512,9 @@ BOOL _reset_device(WINPR_COMM *pComm) return TRUE; } -static REMOTE_SERIAL_DRIVER _SerialSys = +static SERIAL_DRIVER _SerialSys = { - .id = RemoteSerialDriverSerialSys, + .id = SerialDriverSerialSys, .name = _T("Serial.sys"), .set_baud_rate = _set_baud_rate, .get_baud_rate = _get_baud_rate, @@ -1549,7 +1549,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = }; -REMOTE_SERIAL_DRIVER* SerialSys_s() +SERIAL_DRIVER* SerialSys_s() { return &_SerialSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.h b/winpr/libwinpr/comm/comm_serial_sys.h index 6858437b3..e99c716d2 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.h +++ b/winpr/libwinpr/comm/comm_serial_sys.h @@ -28,7 +28,7 @@ extern "C" { #endif -REMOTE_SERIAL_DRIVER* SerialSys_s(); +SERIAL_DRIVER* SerialSys_s(); #ifdef __cplusplus } diff --git a/winpr/libwinpr/comm/test/TestGetCommState.c b/winpr/libwinpr/comm/test/TestGetCommState.c index c6a2747e9..1a4df956f 100644 --- a/winpr/libwinpr/comm/test/TestGetCommState.c +++ b/winpr/libwinpr/comm/test/TestGetCommState.c @@ -94,28 +94,28 @@ int TestGetCommState(int argc, char* argv[]) if (!test_generic(hComm)) { - printf("test_generic failure (RemoteSerialDriverUnknown)\n"); + printf("test_generic failure (SerialDriverUnknown)\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); if (!test_generic(hComm)) { - printf("test_generic failure (RemoteSerialDriverSerialSys)\n"); + printf("test_generic failure (SerialDriverSerialSys)\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); if (!test_generic(hComm)) { - printf("test_generic failure (RemoteSerialDriverSerCxSys)\n"); + printf("test_generic failure (SerialDriverSerCxSys)\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); if (!test_generic(hComm)) { - printf("test_generic failure (RemoteSerialDriverSerCx2Sys)\n"); + printf("test_generic failure (SerialDriverSerCx2Sys)\n"); return EXIT_FAILURE; } diff --git a/winpr/libwinpr/comm/test/TestHandflow.c b/winpr/libwinpr/comm/test/TestHandflow.c index 471e5488e..098b8b0e6 100644 --- a/winpr/libwinpr/comm/test/TestHandflow.c +++ b/winpr/libwinpr/comm/test/TestHandflow.c @@ -54,21 +54,21 @@ int TestHandflow(int argc, char* argv[]) return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); if (!test_SerialSys(hComm)) { fprintf(stderr, "test_SerCxSys failure\n"); return EXIT_FAILURE; } - /* _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); */ + /* _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); */ /* if (!test_SerCxSys(hComm)) */ /* { */ /* fprintf(stderr, "test_SerCxSys failure\n"); */ /* return EXIT_FAILURE; */ /* } */ - /* _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); */ + /* _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); */ /* if (!test_SerCx2Sys(hComm)) */ /* { */ /* fprintf(stderr, "test_SerCxSys failure\n"); */ diff --git a/winpr/libwinpr/comm/test/TestSerialChars.c b/winpr/libwinpr/comm/test/TestSerialChars.c index 1a8f65332..d17c2f844 100644 --- a/winpr/libwinpr/comm/test/TestSerialChars.c +++ b/winpr/libwinpr/comm/test/TestSerialChars.c @@ -148,14 +148,14 @@ int TestSerialChars(int argc, char* argv[]) return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); if (!test_SerCxSys(hComm)) { fprintf(stderr, "test_SerCxSys failure\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); if (!test_SerCx2Sys(hComm)) { fprintf(stderr, "test_SerCxSys failure\n"); diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c index a152dd197..9c06263c6 100644 --- a/winpr/libwinpr/comm/test/TestSetCommState.c +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -339,14 +339,14 @@ int TestSetCommState(int argc, char* argv[]) if (!test_generic(hComm)) { - fprintf(stderr, "test_generic failure (RemoteSerialDriverUnknown)\n"); + fprintf(stderr, "test_generic failure (SerialDriverUnknown)\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); if (!test_generic(hComm)) { - fprintf(stderr, "test_generic failure (RemoteSerialDriverSerialSys)\n"); + fprintf(stderr, "test_generic failure (SerialDriverSerialSys)\n"); return EXIT_FAILURE; } if (!test_SerialSys(hComm)) @@ -356,10 +356,10 @@ int TestSetCommState(int argc, char* argv[]) } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); if (!test_generic(hComm)) { - fprintf(stderr, "test_generic failure (RemoteSerialDriverSerCxSys)\n"); + fprintf(stderr, "test_generic failure (SerialDriverSerCxSys)\n"); return EXIT_FAILURE; } if (!test_SerCxSys(hComm)) @@ -368,10 +368,10 @@ int TestSetCommState(int argc, char* argv[]) return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); if (!test_generic(hComm)) { - fprintf(stderr, "test_generic failure (RemoteSerialDriverSerCx2Sys)\n"); + fprintf(stderr, "test_generic failure (SerialDriverSerCx2Sys)\n"); return EXIT_FAILURE; } if (!test_SerCx2Sys(hComm)) diff --git a/winpr/libwinpr/comm/test/TestTimeouts.c b/winpr/libwinpr/comm/test/TestTimeouts.c index 3045f486d..4f6c89424 100644 --- a/winpr/libwinpr/comm/test/TestTimeouts.c +++ b/winpr/libwinpr/comm/test/TestTimeouts.c @@ -95,21 +95,21 @@ int TestTimeouts(int argc, char* argv[]) return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); if (!test_generic(hComm)) { fprintf(stderr, "test_SerialSys failure\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); if (!test_generic(hComm)) { fprintf(stderr, "test_SerCxSys failure\n"); return EXIT_FAILURE; } - _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); if (!test_generic(hComm)) { fprintf(stderr, "test_SerCx2Sys failure\n"); From e6c82f99d5756ecc0eb625f0091cc1ac59c77b51 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 18 Jun 2014 18:20:21 +0200 Subject: [PATCH 56/61] serial: ability to setup the server serial driver thanks to a third parameter on the command line --- channels/serial/client/serial_main.c | 30 ++++++++++++++++++++++++++++ client/common/cmdline.c | 3 +++ include/freerdp/settings.h | 1 + libfreerdp/common/settings.c | 10 ++++++++++ winpr/include/winpr/comm.h | 19 ++++++++++++++++++ winpr/libwinpr/comm/comm.c | 10 ++-------- winpr/libwinpr/comm/comm.h | 14 ------------- 7 files changed, 65 insertions(+), 22 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 0e6d078a5..b721d4295 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -64,6 +64,7 @@ typedef struct _SERIAL_DEVICE SERIAL_DEVICE; struct _SERIAL_DEVICE { DEVICE device; + SERIAL_DRIVER_ID ServerSerialDriverId; HANDLE* hComm; /* TODO: use of log (prefered the old fashion DEBUG_SVC and @@ -193,6 +194,8 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) goto error_handle; } + _comm_setServerSerialDriver(serial->hComm, serial->ServerSerialDriverId); + /* FIXME: Appeared to be useful to setup some devices. Guess * the device driver asked to setup some unsupported feature * that were not eventually used. TODO: collecting more @@ -744,12 +747,14 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) int i, len; char* name; char* path; + char* driver; RDPDR_SERIAL* device; SERIAL_DEVICE* serial; device = (RDPDR_SERIAL*) pEntryPoints->device; name = device->Name; path = device->Path; + driver = device->Driver; if (!name || (name[0] == '*')) { @@ -782,6 +787,31 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) for (i = 0; i <= len; i++) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); + if (driver != NULL) + { + if (_stricmp(driver, "Serial") == 0) + serial->ServerSerialDriverId = SerialDriverSerialSys; + else if (_stricmp(driver, "SerCx") == 0) + serial->ServerSerialDriverId = SerialDriverSerCxSys; + else if (_stricmp(driver, "SerCx2") == 0) + serial->ServerSerialDriverId = SerialDriverSerCx2Sys; + else + { + assert(FALSE); + + DEBUG_SVC("Unknown server's serial driver: %s. SerCx2 will be used", driver); + serial->ServerSerialDriverId = SerialDriverSerCx2Sys; + } + } + else + { + /* default driver */ + serial->ServerSerialDriverId = SerialDriverSerCx2Sys; + } + + DEBUG_SVC("Server's serial driver: %s (id: %d)", driver, serial->ServerSerialDriverId); + /* TODO: implement auto detection of the server's serial driver */ + serial->MainIrpQueue = MessageQueue_New(NULL); /* IrpThreads content only modified by create_irp_thread() */ diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 2e4d2f01f..1adb5580f 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -385,6 +385,9 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p if (count > 2) serial->Path = _strdup(params[2]); + if (count > 3) + serial->Driver = _strdup(params[3]); + freerdp_device_collection_add(settings, (RDPDR_DEVICE*) serial); settings->DeviceRedirection = TRUE; diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 92d3ac45c..b23b3fabf 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -466,6 +466,7 @@ struct _RDPDR_SERIAL UINT32 Type; char* Name; char* Path; + char* Driver; }; typedef struct _RDPDR_SERIAL RDPDR_SERIAL; diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 3eab8ce69..00772f7b8 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -287,8 +287,17 @@ out_smartc_name_error: goto out_serial_path_error; } + if (serial->Driver) + { + _serial->Driver = _strdup(serial->Driver); + if (!_serial->Driver) + goto out_serial_driver_error; + } + return (RDPDR_DEVICE*) _serial; +out_serial_driver_error: + free(_serial->Path); out_serial_path_error: free(_serial->Name); out_serial_name_error: @@ -360,6 +369,7 @@ void freerdp_device_collection_free(rdpSettings* settings) else if (settings->DeviceArray[index]->Type == RDPDR_DTYP_SERIAL) { free(((RDPDR_SERIAL*) device)->Path); + free(((RDPDR_SERIAL*) device)->Driver); } else if (settings->DeviceArray[index]->Type == RDPDR_DTYP_PARALLEL) { diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 55803741b..3398906d1 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -383,6 +383,20 @@ WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOver #define MAXULONG (4294967295UL) #endif + +/** + * IOCTLs table according the server's serial driver: + * http://msdn.microsoft.com/en-us/library/windows/hardware/dn265347%28v=vs.85%29.aspx + */ +typedef enum _SERIAL_DRIVER_ID +{ + SerialDriverUnknown = 0, + SerialDriverSerialSys, + SerialDriverSerCxSys, + SerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */ +} SERIAL_DRIVER_ID; + + /* * About DefineCommDevice() / QueryDosDevice() * @@ -534,6 +548,11 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = */ const char* _comm_serial_ioctl_name(ULONG number); +/** + * FIXME: got a proper function name and place + */ +void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID); + /** * FIXME: got a proper function name and place * diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 14829d1df..39bde3bc1 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -347,7 +347,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) WINPR_COMM* pComm = (WINPR_COMM*) hFile; DWORD bytesReturned; - // TMP: FIXME: validate changes according GetCommProperties + /* FIXME: validate changes according GetCommProperties? */ if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) { @@ -538,8 +538,6 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) upcomingTermios.c_iflag &= ~INPCK; } - // TMP: TODO: - // (...) /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx * @@ -1160,11 +1158,7 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare InitializeCriticalSection(&pComm->WriteLock); - - /* TMP: TODO: FIXME: this information is at least needed for - * get/set baud functions. Is it possible to pull this - * information? Could be a command line argument. - */ + /* can also be setup later on with _comm_setServerSerialDriver() */ pComm->serverSerialDriverId = SerialDriverUnknown; InitializeCriticalSection(&pComm->EventsLock); diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 84952f4fc..b2ee8d4ac 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -30,18 +30,6 @@ #include "../handle/handle.h" -/** - * IOCTLs table according the remote serial driver: - * http://msdn.microsoft.com/en-us/library/windows/hardware/dn265347%28v=vs.85%29.aspx - */ -typedef enum _SERIAL_DRIVER_ID -{ - SerialDriverUnknown = 0, - SerialDriverSerialSys, - SerialDriverSerCxSys, - SerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */ -} SERIAL_DRIVER_ID; - struct winpr_comm { WINPR_HANDLE_DEF(); @@ -79,8 +67,6 @@ struct winpr_comm typedef struct winpr_comm WINPR_COMM; -void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID); - /* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ #define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit unused by SERIAL_EV_* */ #define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ From d38a323526088f5eb679ff51c03e4373343fc0ef Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Thu, 19 Jun 2014 12:03:36 +0200 Subject: [PATCH 57/61] winpr-comm, winpr-file: better initialization of the static variables --- winpr/include/winpr/file.h | 2 +- winpr/libwinpr/comm/comm.c | 55 ++++++++++++++++++++++++-------------- winpr/libwinpr/file/file.c | 53 +++++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 37 deletions(-) diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index 9f8d748a8..ef5c4dd54 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -321,7 +321,7 @@ typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD typedef struct _HANDLE_CREATOR { pcIsHandled IsHandled; - pcCreateFileA CreateFileA; /* TMP: FIXME: CreateFileA or CreateFile ? */ + pcCreateFileA CreateFileA; } HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator); diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 39bde3bc1..b99d53255 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -26,15 +26,16 @@ #ifndef _WIN32 +#include +#include #include +#include #include #include #include #include #include -#include - #include #include @@ -749,31 +750,33 @@ typedef struct _COMM_DEVICE } COMM_DEVICE; /* FIXME: get a clever data structure, see also io.h functions */ -static COMM_DEVICE **_CommDevices = NULL; - +/* _CommDevices is a NULL-terminated array with a maximun of COMM_DEVICE_MAX COMM_DEVICE */ #define COMM_DEVICE_MAX 128 +static COMM_DEVICE **_CommDevices = NULL; static HANDLE_CREATOR *_CommHandleCreator = NULL; - -static void _CommDevicesInit() +static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT; +static void _CommInit() { - /* - * TMP: FIXME: What kind of mutex should be used here? - * better have to let DefineCommDevice() and QueryCommDevice() thread unsafe ? - * use of a module_init() ? - */ + /* NB: error management to be done outside of this function */ - if (_CommDevices == NULL) + assert(_CommDevices == NULL); + assert(_CommHandleCreator == NULL); + + _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); + + _CommHandleCreator = (HANDLE_CREATOR*)malloc(sizeof(HANDLE_CREATOR)); + if (_CommHandleCreator) { - _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); - - _CommHandleCreator = (HANDLE_CREATOR*)malloc(sizeof(HANDLE_CREATOR)); _CommHandleCreator->IsHandled = IsCommDevice; _CommHandleCreator->CreateFileA = CommCreateFileA; - + RegisterHandleCreator(_CommHandleCreator); } + + assert(_CommDevices != NULL); + assert(_CommHandleCreator != NULL); } @@ -818,6 +821,7 @@ static BOOL _IsReservedCommDeviceName(LPCTSTR lpName) * information, call GetLastError. * * ERRORS: + * ERROR_DLL_INIT_FAILED * ERROR_OUTOFMEMORY was not possible to get mappings. * ERROR_INVALID_DATA was not possible to add the device. */ @@ -827,10 +831,15 @@ BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTarget LPTSTR storedDeviceName = NULL; LPTSTR storedTargetPath = NULL; - _CommDevicesInit(); + if (pthread_once(&_CommInitialized, _CommInit) != 0) + { + SetLastError(ERROR_DLL_INIT_FAILED); + goto error_handle; + } + if (_CommDevices == NULL) { - SetLastError(ERROR_OUTOFMEMORY); + SetLastError(ERROR_DLL_INIT_FAILED); goto error_handle; } @@ -918,6 +927,7 @@ BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTarget * * ERRORS: * ERROR_SUCCESS + * ERROR_DLL_INIT_FAILED * ERROR_OUTOFMEMORY was not possible to get mappings. * ERROR_NOT_SUPPORTED equivalent QueryDosDevice feature not supported. * ERROR_INVALID_DATA was not possible to retrieve any device information. @@ -930,10 +940,15 @@ DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) SetLastError(ERROR_SUCCESS); - _CommDevicesInit(); + if (pthread_once(&_CommInitialized, _CommInit) != 0) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return 0; + } + if (_CommDevices == NULL) { - SetLastError(ERROR_OUTOFMEMORY); + SetLastError(ERROR_DLL_INIT_FAILED); return 0; } diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 4908a7191..a48e1befa 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -42,7 +42,7 @@ /** * api-ms-win-core-file-l1-2-0.dll: - * + * * CreateFileA * CreateFileW * CreateFile2 @@ -150,8 +150,10 @@ #include #endif +#include #include #include +#include #include #include #include @@ -190,34 +192,45 @@ * winpr-collections to avoid a circular dependency * _HandleCreators = ArrayList_New(TRUE); */ +/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */ +#define HANDLE_CREATOR_MAX 128 static HANDLE_CREATOR **_HandleCreators = NULL; -#define HANDLE_CREATOR_MAX 128 - +static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT; static void _HandleCreatorsInit() { - /* - * TMP: FIXME: What kind of mutex should be used here? use of - * a module_init()? - */ + /* NB: error management to be done outside of this function */ - if (_HandleCreators == NULL) - { - _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*)); - } + assert(_HandleCreators == NULL); + + _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*)); + + assert(_HandleCreators != NULL); } /** * Returns TRUE on success, FALSE otherwise. * * ERRORS: + * ERROR_DLL_INIT_FAILED * ERROR_INSUFFICIENT_BUFFER _HandleCreators full */ BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator) { int i; - _HandleCreatorsInit(); + if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + if (_HandleCreators == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + for (i=0; i Date: Thu, 19 Jun 2014 19:07:45 +0200 Subject: [PATCH 58/61] winpr-handle: CloseHandle(), added ability to register some callback functions winpr-comm: implemented CommCloseHandle() --- channels/serial/client/serial_main.c | 3 + winpr/include/winpr/file.h | 4 +- winpr/libwinpr/comm/comm.c | 77 +++++++++++++++++++ winpr/libwinpr/comm/comm.h | 3 + winpr/libwinpr/comm/comm_ioctl.c | 10 ++- winpr/libwinpr/handle/handle.c | 109 ++++++++++++++++++--------- winpr/libwinpr/handle/handle.h | 12 +++ 7 files changed, 177 insertions(+), 41 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index b721d4295..e2d7871c0 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -385,6 +385,9 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) error_handle: + /* FIXME: find out whether it's required or not to get + * BytesReturned == OutputBufferLength when + * CommDeviceIoControl returns FALSE */ assert(OutputBufferLength == BytesReturned); Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */ diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index ef5c4dd54..b54c46e63 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -314,13 +314,13 @@ WINPR_API BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecu /* Extra Functions */ -typedef BOOL (*pcIsHandled)(LPCSTR lpFileName); +typedef BOOL (*pcIsFileHandled)(LPCSTR lpFileName); typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); typedef struct _HANDLE_CREATOR { - pcIsHandled IsHandled; + pcIsFileHandled IsHandled; pcCreateFileA CreateFileA; } HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index b99d53255..dea659353 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -755,6 +755,7 @@ typedef struct _COMM_DEVICE static COMM_DEVICE **_CommDevices = NULL; static HANDLE_CREATOR *_CommHandleCreator = NULL; +static HANDLE_CLOSE_CB *_CommHandleCloseCb = NULL; static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT; static void _CommInit() @@ -763,6 +764,7 @@ static void _CommInit() assert(_CommDevices == NULL); assert(_CommHandleCreator == NULL); + assert(_CommHandleCloseCb == NULL); _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); @@ -775,8 +777,18 @@ static void _CommInit() RegisterHandleCreator(_CommHandleCreator); } + _CommHandleCloseCb = (HANDLE_CLOSE_CB*)malloc(sizeof(HANDLE_CLOSE_CB)); + if (_CommHandleCloseCb) + { + _CommHandleCloseCb->IsHandled = CommIsHandled; + _CommHandleCloseCb->CloseHandle = CommCloseHandle; + + RegisterHandleCloseCb(_CommHandleCloseCb); + } + assert(_CommDevices != NULL); assert(_CommHandleCreator != NULL); + assert(_CommHandleCloseCb != NULL); } @@ -1232,4 +1244,69 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } +BOOL CommIsHandled(HANDLE handle) +{ + WINPR_COMM *pComm; + + pComm = (WINPR_COMM*)handle; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + return TRUE; +} + + +BOOL CommCloseHandle(HANDLE handle) +{ + WINPR_COMM *pComm; + + pComm = (WINPR_COMM*)handle; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + { + ULONG WaitMask = 0; + DWORD BytesReturned = 0; + + /* ensures to gracefully stop the WAIT_ON_MASK's loop */ + if (!CommDeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK, &WaitMask, sizeof(ULONG), NULL, 0, &BytesReturned, NULL)) + { + DEBUG_WARN("failure to WAIT_ON_MASK's loop!"); + } + } + + DeleteCriticalSection(&pComm->ReadLock); + DeleteCriticalSection(&pComm->WriteLock); + DeleteCriticalSection(&pComm->EventsLock); + + if (pComm->fd > 0) + close(pComm->fd); + + if (pComm->fd_write > 0) + close(pComm->fd_write); + + if (pComm->fd_write_event > 0) + close(pComm->fd_write_event); + + if (pComm->fd_read > 0) + close(pComm->fd_read); + + if (pComm->fd_read_event > 0) + close(pComm->fd_read_event); + + free(pComm); + + return TRUE; +} + + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index b2ee8d4ac..763a566d2 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -74,6 +74,9 @@ typedef struct winpr_comm WINPR_COMM; #define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */ #define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */ +BOOL CommIsHandled(HANDLE handle); +BOOL CommCloseHandle(HANDLE handle); + #endif /* _WIN32 */ #endif /* WINPR_COMM_PRIVATE_H */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 3770a6f7b..9572bbd51 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -462,7 +462,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask)) { - *lpBytesReturned = sizeof(ULONG); /* TMP: TODO: all lpBytesReturned values to be reviewed on error */ + *lpBytesReturned = sizeof(ULONG); return FALSE; } @@ -670,6 +670,12 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe result = _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 */ + DEBUG_WARN("lpBytesReturned=%d and nOutBufferSize=%d are different!", *lpBytesReturned, nOutBufferSize); + } + if (pComm->permissive) { if (!result) @@ -722,7 +728,7 @@ int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *te if (memcmp(¤tState, termios_p, sizeof(struct termios)) != 0) { DEBUG_WARN("Failure: all termios parameters are still not set on a second attempt"); - return -1; /* TMP: double-check whether some parameters can differ anyway */ + return -1; } } diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 0cee4b391..57cf98547 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -25,6 +25,9 @@ #ifndef _WIN32 +#include +#include + #include "../synch/synch.h" #include "../thread/thread.h" #include "../pipe/pipe.h" @@ -37,14 +40,83 @@ #include "../handle/handle.h" +/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */ +#define HANDLE_CLOSE_CB_MAX 128 +static HANDLE_CLOSE_CB **_HandleCloseCbs = NULL; + +static pthread_once_t _HandleCloseCbsInitialized = PTHREAD_ONCE_INIT; +static void _HandleCloseCbsInit() +{ + /* NB: error management to be done outside of this function */ + + assert(_HandleCloseCbs == NULL); + + _HandleCloseCbs = (HANDLE_CLOSE_CB**)calloc(HANDLE_CLOSE_CB_MAX+1, sizeof(HANDLE_CLOSE_CB*)); + + assert(_HandleCloseCbs != NULL); +} + +/** + * Returns TRUE on success, FALSE otherwise. + */ +BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleCloseCb) +{ + int i; + + if (pthread_once(&_HandleCloseCbsInitialized, _HandleCloseCbsInit) != 0) + { + return FALSE; + } + + if (_HandleCloseCbs == NULL) + { + return FALSE; + } + + + for (i=0; iIsHandled(hObject)) + { + return close_cb->CloseHandle(hObject); + } + } + + if (Type == HANDLE_TYPE_THREAD) { WINPR_THREAD* thread; @@ -197,43 +269,6 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } - else if (Type == HANDLE_TYPE_COMM) - { - WINPR_COMM* comm; - - comm = (WINPR_COMM*) Object; - - /* NOTE: This is up to the caller of CloseHandle() to - * ensure there is no pending request. Sending - * SERIAL_EV_FREERDP_STOP anyway. Remove this code if - * you think otherwise. */ - EnterCriticalSection(&comm->EventsLock); - comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; - LeaveCriticalSection(&comm->EventsLock); - - DeleteCriticalSection(&comm->ReadLock); - DeleteCriticalSection(&comm->WriteLock); - DeleteCriticalSection(&comm->EventsLock); - - if (comm->fd > 0) - close(comm->fd); - - if (comm->fd_write > 0) - close(comm->fd_write); - - if (comm->fd_write_event > 0) - close(comm->fd_write_event); - - if (comm->fd_read > 0) - close(comm->fd_read); - - if (comm->fd_read_event > 0) - close(comm->fd_read_event); - - free(comm); - - return TRUE; - } return FALSE; } diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index e5b6bae72..6a2630822 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -64,4 +64,16 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj return TRUE; } + +typedef BOOL (*pcIsHandled)(HANDLE handle); +typedef BOOL (*pcCloseHandle)(HANDLE handle); + +typedef struct _HANDLE_CLOSE_CB +{ + pcIsHandled IsHandled; + pcCloseHandle CloseHandle; +} HANDLE_CLOSE_CB; + +BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleClose); + #endif /* WINPR_HANDLE_PRIVATE_H */ From b2bfc8004c5965d659e03e68e75498e2317055ab Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 20 Jun 2014 15:56:41 +0200 Subject: [PATCH 59/61] winpr-comm: gathered together all SERIAL_EV_* #defines --- winpr/libwinpr/comm/comm.h | 18 +++++++++++++++--- winpr/libwinpr/comm/comm_ioctl.h | 15 --------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 763a566d2..800dcb5c7 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -67,9 +67,21 @@ struct winpr_comm typedef struct winpr_comm WINPR_COMM; -/* TMP: TODO: move all specific defines and types here? at least SERIAL_EV_* */ -#define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit unused by SERIAL_EV_* */ -#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit unused by SERIAL_EV_* */ +#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_FREERDP_WAITING 0x4000 /* bit today unused by other SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit today unused by other SERIAL_EV_* */ #define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */ #define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */ diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index 99ada3154..bb1e3b3d4 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -147,21 +147,6 @@ typedef struct _SERIAL_TIMEOUTS #define SERIAL_MSR_RI 0x40 #define SERIAL_MSR_DCD 0x80 - -#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 - typedef struct _SERIAL_QUEUE_SIZE { ULONG InSize; From 11ed1f122f02de26ffec677cbe6e600c192fa3dd Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Fri, 20 Jun 2014 16:30:59 +0200 Subject: [PATCH 60/61] winpr-comm: comm_serial_sys, got rid of the latest TMP tags --- winpr/libwinpr/comm/comm_serial_sys.c | 40 +++++++++++---------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index aafce8a61..01a04abdb 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -145,12 +145,12 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) /* FIXME: what about PST_RS232? see also: serial_struct */ pProperties->dwProvSubType = PST_UNSPECIFIED; - /* TMP: TODO: to be finalized */ + /* TODO: to be finalized */ pProperties->dwProvCapabilities = - /*PCF_16BITMODE | PCF_DTRDSR |*/ PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD | */ - PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS | PCF_TOTALTIMEOUTS |*/ PCF_XONXOFF; + /*PCF_16BITMODE |*/ PCF_DTRDSR | PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD |*/ + PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS |*/ PCF_TOTALTIMEOUTS | PCF_XONXOFF; - /* TMP: TODO: double check SP_RLSD */ + /* TODO: double check SP_RLSD */ pProperties->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY | SP_PARITY_CHECK | /*SP_RLSD |*/ SP_STOPBITS; pProperties->dwSettableBaud = 0; @@ -310,7 +310,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar result = FALSE; /* but keep on */ } - /* TMP: FIXME: Didn't find anything similar yet on Linux. What about ISIG? */ + /* FIXME: could be implemented during read/write I/O. What about ISIG? */ if (pSerialChars->EventChar != '\0') { DEBUG_WARN("EventChar='%c' (0x%x) cannot be set\n", pSerialChars->EventChar, pSerialChars->EventChar); @@ -352,7 +352,7 @@ static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars) /* BreakChar unsupported */ - /* TMP: FIXME: see also: _set_serial_chars() */ + /* FIXME: see also: _set_serial_chars() */ /* EventChar */ pSerialChars->XonChar = currentTermios.c_cc[VSTART]; @@ -609,7 +609,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) result = FALSE; /* but keep on */ } - // TMP: FIXME: could be implemented during read/write I/O + // FIXME: could be implemented during read/write I/O if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) { /* DSR line control not supported on Linux */ @@ -618,7 +618,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) result = FALSE; /* but keep on */ } - // TMP: FIXME: could be implemented during read/write I/O + // FIXME: could be implemented during read/write I/O if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) { /* Aborting operations on error not supported on Linux */ @@ -647,7 +647,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) upcomingTermios.c_iflag &= ~IXOFF; } - // TMP: FIXME: could be implemented during read/write I/O, as of today ErrorChar is necessary '\0' + // FIXME: could be implemented during read/write I/O, as of today ErrorChar is necessary '\0' if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR) { /* errors will be replaced by the character '\0'. */ @@ -667,7 +667,7 @@ static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) upcomingTermios.c_iflag &= ~IGNBRK; } - // TMP: FIXME: could be implemented during read/write I/O + // FIXME: could be implemented during read/write I/O if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR) { DEBUG_WARN("Attempt to use the unsupported SERIAL_BREAK_CHAR feature."); @@ -1038,18 +1038,6 @@ static BOOL _get_wait_mask(WINPR_COMM *pComm, ULONG *pWaitMask) static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSize) { - -/* TMP: FIXME: do at least a purge/reset ? */ -/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx */ -/* A process reinitializes a communications resource by using the SetupComm function, which performs the following tasks: */ - -/* Terminates pending read and write operations, even if they have not been completed. */ -/* Discards unread characters and frees the internal output and input buffers of the driver associated with the specified resource. */ -/* Reallocates the internal output and input buffers. */ - -/* A process is not required to call SetupComm. If it does not, the resource's driver initializes the device with the default settings the first time that the communications resource handle is used. */ - - if ((pQueueSize->InSize <= N_TTY_BUF_SIZE) && (pQueueSize->OutSize <= N_TTY_BUF_SIZE)) return TRUE; /* nothing to do */ @@ -1240,7 +1228,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) /* BOOLEAN EofReceived; FIXME: once EofChar supported */ - /* BOOLEAN WaitForImmediate; TMP: TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR supported */ + /* BOOLEAN WaitForImmediate; TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR fully supported */ /* other events based on counters */ @@ -1496,7 +1484,11 @@ BOOL _immediate_char(WINPR_COMM *pComm, const UCHAR *pChar) BOOL result; DWORD nbBytesWritten = -1; - /* FIXME: CommWriteFile uses a critical section, shall it be interrupted? */ + /* FIXME: CommWriteFile uses a critical section, shall it be + * interrupted? + * + * FIXME: see also _get_commstatus()'s WaitForImmediate boolean + */ result = CommWriteFile(pComm, pChar, 1, &nbBytesWritten, NULL); From d93c6b1362d0f290400faff8d8fc065cacab9d03 Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 25 Jun 2014 17:02:10 +0200 Subject: [PATCH 61/61] serial: don't use wlog API yet winpr-comm: cleared some #warnings due to wrong printf formats --- channels/serial/client/serial_main.c | 34 +++++++++++++-------------- winpr/libwinpr/comm/comm_ioctl.c | 2 +- winpr/libwinpr/comm/comm_serial_sys.c | 4 ++-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index e2d7871c0..9c5cade51 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -48,9 +48,7 @@ #include #include #include -#include - -#include +/* #include */ #include #include @@ -70,7 +68,7 @@ struct _SERIAL_DEVICE /* TODO: use of log (prefered the old fashion DEBUG_SVC and * DEBUG_WARN macros for backward compatibility resaons) */ - wLog* log; + /* wLog* log; */ HANDLE MainThread; wMessageQueue* MainIrpQueue; @@ -130,7 +128,7 @@ static UINT32 _GetLastErrorToIoStatus() /* no default */ } - DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + DEBUG_SVC("unexpected last-error: 0x%lx", GetLastError()); return STATUS_UNSUCCESSFUL; } @@ -170,7 +168,7 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) * */ - DEBUG_SVC("DesiredAccess: 0x%0.8x, SharedAccess: 0x%0.8x, CreateDisposition: 0x%0.8x", DesiredAccess, SharedAccess, CreateDisposition); + DEBUG_SVC("DesiredAccess: 0x%lX, SharedAccess: 0x%lX, CreateDisposition: 0x%lX", DesiredAccess, SharedAccess, CreateDisposition); /* FIXME: As of today only the flags below are supported by CommCreateFileA: */ DesiredAccess = GENERIC_READ | GENERIC_WRITE; @@ -268,7 +266,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) */ - DEBUG_SVC("reading %lu bytes from %s", Length, serial->device.name); + DEBUG_SVC("reading %d bytes from %s", Length, serial->device.name); /* FIXME: CommReadFile to be replaced by ReadFile */ if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL)) @@ -277,7 +275,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8X", serial->device.name, nbRead, GetLastError()); + DEBUG_SVC("read failure to %s, nbRead=%ld, last-error: 0x%lX", serial->device.name, nbRead, GetLastError()); irp->IoStatus = _GetLastErrorToIoStatus(); } @@ -315,7 +313,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) * set. */ - DEBUG_SVC("writing %lu bytes to %s", Length, serial->device.name); + DEBUG_SVC("writing %d bytes to %s", Length, serial->device.name); /* FIXME: CommWriteFile to be replaced by WriteFile */ if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten, NULL)) @@ -324,7 +322,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8X", serial->device.name, nbWritten, GetLastError()); + DEBUG_SVC("write failure to %s, nbWritten=%ld, last-error: 0x%lX", serial->device.name, nbWritten, GetLastError()); irp->IoStatus = _GetLastErrorToIoStatus(); } @@ -377,7 +375,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%X", + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%X] %s, last-error: 0x%lX", IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); irp->IoStatus = _GetLastErrorToIoStatus(); @@ -415,8 +413,8 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) { - WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n", - irp->MajorFunction, irp->MinorFunction); + /* WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n", */ + /* irp->MajorFunction, irp->MinorFunction); */ switch (irp->MajorFunction) { @@ -529,7 +527,7 @@ static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) { /* unexpected thread state */ - DEBUG_WARN("WaitForSingleObject, got an unexpected result=0x%X\n", waitResult); + DEBUG_WARN("WaitForSingleObject, got an unexpected result=0x%lX\n", waitResult); assert(FALSE); } /* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */ @@ -723,7 +721,7 @@ static void serial_free(DEVICE* device) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; - WLog_Print(serial->log, WLOG_DEBUG, "freeing"); + /* WLog_Print(serial->log, WLOG_DEBUG, "freeing"); */ MessageQueue_PostQuit(serial->MainIrpQueue, 0); WaitForSingleObject(serial->MainThread, INFINITE); @@ -822,9 +820,9 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->IrpThreadToBeTerminatedCount = 0; InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); - WLog_Init(); - serial->log = WLog_Get("com.freerdp.channel.serial.client"); - WLog_Print(serial->log, WLOG_DEBUG, "initializing"); + /* WLog_Init(); */ + /* serial->log = WLog_Get("com.freerdp.channel.serial.client"); */ + /* WLog_Print(serial->log, WLOG_DEBUG, "initializing"); */ pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 9572bbd51..11f608552 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -673,7 +673,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe if (lpBytesReturned && *lpBytesReturned != nOutBufferSize) { /* This might be a hint for a bug, especially when result==TRUE */ - DEBUG_WARN("lpBytesReturned=%d and nOutBufferSize=%d are different!", *lpBytesReturned, nOutBufferSize); + DEBUG_WARN("lpBytesReturned=%ld and nOutBufferSize=%ld are different!", *lpBytesReturned, nOutBufferSize); } if (pComm->permissive) diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 01a04abdb..813c419f7 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1044,10 +1044,10 @@ static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSi /* FIXME: could be implemented on top of N_TTY */ if (pQueueSize->InSize > N_TTY_BUF_SIZE) - DEBUG_WARN("Requested an incompatible input buffer size: %lu, keeping on with a %lu bytes buffer.", pQueueSize->InSize, N_TTY_BUF_SIZE); + DEBUG_WARN("Requested an incompatible input buffer size: %lu, keeping on with a %d bytes buffer.", pQueueSize->InSize, N_TTY_BUF_SIZE); if (pQueueSize->OutSize > N_TTY_BUF_SIZE) - DEBUG_WARN("Requested an incompatible output buffer size: %lu, keeping on with a %lu bytes buffer.", pQueueSize->OutSize, N_TTY_BUF_SIZE); + DEBUG_WARN("Requested an incompatible output buffer size: %lu, keeping on with a %d bytes buffer.", pQueueSize->OutSize, N_TTY_BUF_SIZE); SetLastError(ERROR_CANCELLED); return FALSE;