2014-04-02 23:51:28 +04:00
/**
* WinPR : Windows Portable Runtime
* Serial Communication API
*
2014-04-22 19:04:07 +04:00
* Copyright 2011 O . S . Systems Software Ltda .
* Copyright 2011 Eduardo Fiss Beloni < beloni @ ossystems . com . br >
2014-04-02 23:51:28 +04:00
* Copyright 2014 Marc - Andre Moreau < marcandre . moreau @ gmail . com >
2014-06-16 21:18:45 +04:00
* Copyright 2014 Hewlett - Packard Development Company , L . P .
2014-04-02 23:51:28 +04:00
*
* 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
2014-07-04 19:40:06 +04:00
# if defined __linux__ && !defined ANDROID
2014-04-22 19:04:07 +04:00
2014-06-19 14:03:36 +04:00
# include <assert.h>
# include <errno.h>
2014-04-22 19:04:07 +04:00
# include <fcntl.h>
2014-06-19 14:03:36 +04:00
# include <pthread.h>
2014-07-02 17:59:16 +04:00
# include <stdarg.h>
2014-05-14 18:29:10 +04:00
# include <sys/ioctl.h>
2014-04-25 02:20:48 +04:00
# include <sys/stat.h>
# include <sys/types.h>
2014-04-22 19:04:07 +04:00
# include <termios.h>
2014-04-25 02:20:48 +04:00
# include <unistd.h>
2014-04-02 23:51:28 +04:00
# include <winpr/crt.h>
# include <winpr/comm.h>
2014-04-18 19:18:08 +04:00
# include <winpr/tchar.h>
2014-07-02 17:59:16 +04:00
# include <winpr/wlog.h>
2014-04-02 23:51:28 +04:00
2014-04-28 21:57:17 +04:00
# include "comm_ioctl.h"
2014-04-02 23:51:28 +04:00
/**
* Communication Resources :
* http : //msdn.microsoft.com/en-us/library/windows/desktop/aa363196/
*/
# include "comm.h"
2014-07-02 17:59:16 +04:00
static wLog * _Log = NULL ;
struct comm_device
{
LPTSTR name ;
LPTSTR path ;
} ;
typedef struct comm_device COMM_DEVICE ;
/* FIXME: get a clever data structure, see also io.h functions */
/* _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 ;
2014-07-03 13:07:48 +04:00
static CRITICAL_SECTION _CommDevicesLock ;
2014-07-02 17:59:16 +04:00
static HANDLE_CREATOR * _CommHandleCreator = NULL ;
static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT ;
2015-03-11 19:57:01 +03:00
static int CommGetFd ( HANDLE handle )
{
WINPR_COMM * comm = ( WINPR_COMM * ) handle ;
if ( ! CommIsHandled ( handle ) )
return - 1 ;
return comm - > fd ;
}
2014-07-02 17:59:16 +04:00
static void _CommInit ( )
{
/* NB: error management to be done outside of this function */
assert ( _Log = = NULL ) ;
assert ( _CommDevices = = NULL ) ;
assert ( _CommHandleCreator = = NULL ) ;
_CommDevices = ( COMM_DEVICE * * ) calloc ( COMM_DEVICE_MAX + 1 , sizeof ( COMM_DEVICE * ) ) ;
2015-04-03 17:21:01 +03:00
if ( ! _CommDevices )
return ;
if ( ! InitializeCriticalSectionEx ( & _CommDevicesLock , 0 , 0 ) )
{
free ( _CommDevices ) ;
_CommDevices = NULL ;
return ;
}
2014-07-02 17:59:16 +04:00
_CommHandleCreator = ( HANDLE_CREATOR * ) malloc ( sizeof ( HANDLE_CREATOR ) ) ;
2015-04-03 17:21:01 +03:00
if ( ! _CommHandleCreator )
2014-07-02 17:59:16 +04:00
{
2015-04-03 17:21:01 +03:00
DeleteCriticalSection ( & _CommDevicesLock ) ;
free ( _CommDevices ) ;
_CommDevices = NULL ;
return ;
2014-07-02 17:59:16 +04:00
}
2015-04-03 17:21:01 +03:00
_CommHandleCreator - > IsHandled = IsCommDevice ;
_CommHandleCreator - > CreateFileA = CommCreateFileA ;
if ( ! RegisterHandleCreator ( _CommHandleCreator ) )
{
DeleteCriticalSection ( & _CommDevicesLock ) ;
free ( _CommDevices ) ;
free ( _CommHandleCreator ) ;
_CommDevices = NULL ;
_CommHandleCreator = NULL ;
return ;
}
_Log = WLog_Get ( " com.winpr.comm " ) ;
2014-07-02 17:59:16 +04:00
assert ( _Log ! = NULL ) ;
}
/**
* Returns TRUE when the comm module is correctly intialized , FALSE otherwise
* with ERROR_DLL_INIT_FAILED set as the last error .
*/
static BOOL CommInitialized ( )
{
if ( pthread_once ( & _CommInitialized , _CommInit ) ! = 0 )
{
SetLastError ( ERROR_DLL_INIT_FAILED ) ;
return FALSE ;
}
2015-04-03 17:21:01 +03:00
if ( _CommHandleCreator = = NULL )
{
SetLastError ( ERROR_DLL_INIT_FAILED ) ;
return FALSE ;
}
2014-07-02 17:59:16 +04:00
return TRUE ;
}
void CommLog_Print ( int level , char * fmt , . . . )
{
if ( ! CommInitialized ( ) )
return ;
va_list ap ;
va_start ( ap , fmt ) ;
WLog_PrintVA ( _Log , level , fmt , ap ) ;
va_end ( ap ) ;
}
2014-04-02 23:51:28 +04:00
BOOL BuildCommDCBA ( LPCSTR lpDef , LPDCB lpDCB )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL BuildCommDCBW ( LPCWSTR lpDef , LPDCB lpDCB )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL BuildCommDCBAndTimeoutsA ( LPCSTR lpDef , LPDCB lpDCB , LPCOMMTIMEOUTS lpCommTimeouts )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL BuildCommDCBAndTimeoutsW ( LPCWSTR lpDef , LPDCB lpDCB , LPCOMMTIMEOUTS lpCommTimeouts )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL CommConfigDialogA ( LPCSTR lpszName , HWND hWnd , LPCOMMCONFIG lpCC )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL CommConfigDialogW ( LPCWSTR lpszName , HWND hWnd , LPCOMMCONFIG lpCC )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL GetCommConfig ( HANDLE hCommDev , LPCOMMCONFIG lpCC , LPDWORD lpdwSize )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hCommDev ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL SetCommConfig ( HANDLE hCommDev , LPCOMMCONFIG lpCC , DWORD dwSize )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hCommDev ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL GetCommMask ( HANDLE hFile , PDWORD lpEvtMask )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL SetCommMask ( HANDLE hFile , DWORD dwEvtMask )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL GetCommModemStatus ( HANDLE hFile , PDWORD lpModemStat )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
2014-04-29 00:56:25 +04:00
/**
* ERRORS :
2014-07-02 17:59:16 +04:00
* ERROR_DLL_INIT_FAILED
2014-04-29 00:56:25 +04:00
* ERROR_INVALID_HANDLE
*/
2014-04-02 23:51:28 +04:00
BOOL GetCommProperties ( HANDLE hFile , LPCOMMPROP lpCommProp )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-04-29 00:56:25 +04:00
DWORD bytesReturned ;
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-04-29 00:56:25 +04:00
if ( ! pComm | | pComm - > Type ! = HANDLE_TYPE_COMM | | ! pComm - > fd )
{
SetLastError ( ERROR_INVALID_HANDLE ) ;
2014-04-02 23:51:28 +04:00
return FALSE ;
2014-04-29 00:56:25 +04:00
}
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_GET_PROPERTIES , NULL , 0 , lpCommProp , sizeof ( COMMPROP ) , & bytesReturned , NULL ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " GetCommProperties failure. " ) ;
2014-04-29 00:56:25 +04:00
return FALSE ;
}
2014-04-02 23:51:28 +04:00
return TRUE ;
}
2014-04-22 19:04:07 +04:00
/**
2014-06-16 21:18:45 +04:00
*
2014-04-22 19:04:07 +04:00
*
* ERRORS :
* ERROR_INVALID_HANDLE
* ERROR_INVALID_DATA
* ERROR_IO_DEVICE
* ERROR_OUTOFMEMORY
*/
2014-04-02 23:51:28 +04:00
BOOL GetCommState ( HANDLE hFile , LPDCB lpDCB )
{
2014-04-22 19:04:07 +04:00
DCB * lpLocalDcb ;
struct termios currentState ;
2014-04-02 23:51:28 +04:00
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-04-28 21:57:17 +04:00
DWORD bytesReturned ;
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-04-22 19:04:07 +04:00
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 , & currentState ) < 0 )
{
SetLastError ( ERROR_IO_DEVICE ) ;
2014-04-02 23:51:28 +04:00
return FALSE ;
2014-04-22 19:04:07 +04:00
}
2014-04-02 23:51:28 +04:00
2014-04-22 19:04:07 +04:00
lpLocalDcb = ( DCB * ) calloc ( 1 , lpDCB - > DCBlength ) ;
if ( lpLocalDcb = = NULL )
{
SetLastError ( ERROR_OUTOFMEMORY ) ;
return FALSE ;
}
/* error_handle */
2014-06-16 21:18:45 +04:00
2014-04-22 19:04:07 +04:00
lpLocalDcb - > DCBlength = lpDCB - > DCBlength ;
2014-04-28 21:57:17 +04:00
SERIAL_BAUD_RATE baudRate ;
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_GET_BAUD_RATE , NULL , 0 , & baudRate , sizeof ( SERIAL_BAUD_RATE ) , & bytesReturned , NULL ) )
2014-04-22 19:04:07 +04:00
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " GetCommState failure: could not get the baud rate. " ) ;
2014-04-22 19:04:07 +04:00
goto error_handle ;
}
2014-04-28 21:57:17 +04:00
lpLocalDcb - > BaudRate = baudRate . BaudRate ;
2014-06-16 21:18:45 +04:00
2014-05-01 02:04:55 +04:00
lpLocalDcb - > fBinary = ( currentState . c_cflag & ICANON ) = = 0 ;
if ( ! lpLocalDcb - > fBinary )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Unexpected nonbinary mode, consider to unset the ICANON flag. " ) ;
2014-05-01 02:04:55 +04:00
}
2014-04-22 19:04:07 +04:00
2014-06-16 21:18:45 +04:00
lpLocalDcb - > fParity = ( currentState . c_iflag & INPCK ) ! = 0 ;
2014-04-22 19:04:07 +04:00
2014-05-06 18:08:58 +04:00
SERIAL_HANDFLOW handflow ;
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_GET_HANDFLOW , NULL , 0 , & handflow , sizeof ( SERIAL_HANDFLOW ) , & bytesReturned , NULL ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " GetCommState failure: could not get the handflow settings. " ) ;
2014-05-06 18:08:58 +04:00
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 ;
2014-06-16 21:18:45 +04:00
lpLocalDcb - > fTXContinueOnXoff = ( handflow . FlowReplace & SERIAL_XOFF_CONTINUE ) ! = 0 ;
2014-05-06 18:08:58 +04:00
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 ;
2014-04-29 06:04:09 +04:00
2014-04-30 00:25:07 +04:00
SERIAL_LINE_CONTROL lineControl ;
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_GET_LINE_CONTROL , NULL , 0 , & lineControl , sizeof ( SERIAL_LINE_CONTROL ) , & bytesReturned , NULL ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " GetCommState failure: could not get the control settings. " ) ;
2014-04-30 00:25:07 +04:00
goto error_handle ;
}
lpLocalDcb - > ByteSize = lineControl . WordLength ;
lpLocalDcb - > Parity = lineControl . Parity ;
lpLocalDcb - > StopBits = lineControl . StopBits ;
2014-04-29 06:04:09 +04:00
SERIAL_CHARS serialChars ;
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_GET_CHARS , NULL , 0 , & serialChars , sizeof ( SERIAL_CHARS ) , & bytesReturned , NULL ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " GetCommState failure: could not get the serial chars. " ) ;
2014-04-29 06:04:09 +04:00
goto error_handle ;
}
lpLocalDcb - > XonChar = serialChars . XonChar ;
lpLocalDcb - > XoffChar = serialChars . XoffChar ;
lpLocalDcb - > ErrorChar = serialChars . ErrorChar ;
lpLocalDcb - > EofChar = serialChars . EofChar ;
2014-06-16 21:18:45 +04:00
2014-04-29 06:04:09 +04:00
lpLocalDcb - > EvtChar = serialChars . EventChar ;
2014-04-22 19:04:07 +04:00
2014-04-25 02:20:48 +04:00
2014-04-22 19:04:07 +04:00
memcpy ( lpDCB , lpLocalDcb , lpDCB - > DCBlength ) ;
2014-11-17 00:45:09 +03:00
free ( lpLocalDcb ) ;
2014-04-02 23:51:28 +04:00
return TRUE ;
2014-04-22 19:04:07 +04:00
2015-05-11 10:07:39 +03:00
error_handle :
free ( lpLocalDcb ) ;
2014-04-22 19:04:07 +04:00
return FALSE ;
2014-04-02 23:51:28 +04:00
}
2014-04-22 19:04:07 +04:00
/**
2014-04-28 21:57:17 +04:00
* @ return TRUE on success , FALSE otherwise .
2014-06-16 21:18:45 +04:00
*
2014-04-28 21:57:17 +04:00
* 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 ?
*
2014-04-22 19:04:07 +04:00
* ERRORS :
* ERROR_INVALID_HANDLE
* ERROR_IO_DEVICE
*/
2014-04-02 23:51:28 +04:00
BOOL SetCommState ( HANDLE hFile , LPDCB lpDCB )
{
2014-04-28 21:57:17 +04:00
struct termios upcomingTermios ;
2014-04-02 23:51:28 +04:00
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-04-28 21:57:17 +04:00
DWORD bytesReturned ;
2014-06-18 20:20:21 +04:00
/* FIXME: validate changes according GetCommProperties? */
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-04-22 19:04:07 +04:00
if ( ! pComm | | pComm - > Type ! = HANDLE_TYPE_COMM | | ! pComm - > fd )
{
SetLastError ( ERROR_INVALID_HANDLE ) ;
return FALSE ;
}
if ( ! lpDCB )
{
SetLastError ( ERROR_INVALID_DATA ) ;
return FALSE ;
}
2014-04-28 21:57:17 +04:00
/* 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 ) )
2014-04-22 19:04:07 +04:00
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommState failure: could not set the baud rate. " ) ;
2014-04-22 19:04:07 +04:00
return FALSE ;
}
2014-04-29 06:04:09 +04:00
SERIAL_CHARS serialChars ;
2014-05-06 18:08:58 +04:00
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_GET_CHARS , NULL , 0 , & serialChars , sizeof ( SERIAL_CHARS ) , & bytesReturned , NULL ) ) /* as of today, required for BreakChar */
2014-04-29 06:04:09 +04:00
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommState failure: could not get the initial serial chars. " ) ;
2014-04-29 06:04:09 +04:00
return FALSE ;
}
serialChars . XonChar = lpDCB - > XonChar ;
serialChars . XoffChar = lpDCB - > XoffChar ;
serialChars . ErrorChar = lpDCB - > ErrorChar ;
serialChars . EofChar = lpDCB - > EofChar ;
2014-06-16 21:18:45 +04:00
serialChars . EventChar = lpDCB - > EvtChar ;
2014-04-29 06:04:09 +04:00
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_SET_CHARS , & serialChars , sizeof ( SERIAL_CHARS ) , NULL , 0 , & bytesReturned , NULL ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommState failure: could not set the serial chars. " ) ;
2014-04-29 06:04:09 +04:00
return FALSE ;
}
2014-04-28 21:57:17 +04:00
2014-04-30 00:25:07 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommState failure: could not set the control settings. " ) ;
2014-04-30 00:25:07 +04:00
return FALSE ;
}
2014-04-28 21:57:17 +04:00
2014-05-06 18:08:58 +04:00
SERIAL_HANDFLOW handflow ;
ZeroMemory ( & handflow , sizeof ( SERIAL_HANDFLOW ) ) ;
if ( lpDCB - > fOutxCtsFlow )
{
handflow . ControlHandShake | = SERIAL_CTS_HANDSHAKE ;
}
2014-06-16 21:18:45 +04:00
2014-05-06 18:08:58 +04:00
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 :
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Unexpected fDtrControl value: %d \n " , lpDCB - > fDtrControl ) ;
2014-05-06 18:08:58 +04:00
return FALSE ;
}
if ( lpDCB - > fDsrSensitivity )
{
handflow . ControlHandShake | = SERIAL_DSR_SENSITIVITY ;
}
if ( lpDCB - > fTXContinueOnXoff )
{
handflow . FlowReplace | = SERIAL_XOFF_CONTINUE ;
}
2014-06-16 21:18:45 +04:00
2014-05-06 18:08:58 +04:00
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 :
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Unsupported RTS_CONTROL_TOGGLE feature " ) ;
2014-05-06 18:08:58 +04:00
// 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 :
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Unexpected fRtsControl value: %d \n " , lpDCB - > fRtsControl ) ;
2014-05-06 18:08:58 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommState failure: could not set the handflow settings. " ) ;
2014-05-06 18:08:58 +04:00
return FALSE ;
}
2014-04-28 21:57:17 +04:00
/** upcomingTermios stage **/
ZeroMemory ( & upcomingTermios , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & upcomingTermios ) < 0 ) /* NB: preserves current settings not directly handled by the Communication Functions */
2014-04-22 19:04:07 +04:00
{
2014-04-28 21:57:17 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
2014-04-22 19:04:07 +04:00
return FALSE ;
}
2014-05-01 02:04:55 +04:00
if ( lpDCB - > fBinary )
2014-04-22 19:04:07 +04:00
{
2014-05-01 02:04:55 +04:00
upcomingTermios . c_lflag & = ~ ICANON ;
2014-04-22 19:04:07 +04:00
}
2014-05-01 02:04:55 +04:00
else
{
upcomingTermios . c_lflag | = ICANON ;
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Unexpected nonbinary mode, consider to unset the ICANON flag. " ) ;
2014-05-01 02:04:55 +04:00
}
2014-04-22 19:04:07 +04:00
if ( lpDCB - > fParity )
{
2014-05-01 02:04:55 +04:00
upcomingTermios . c_iflag | = INPCK ;
2014-04-22 19:04:07 +04:00
}
else
{
2014-05-01 02:04:55 +04:00
upcomingTermios . c_iflag & = ~ INPCK ;
2014-04-22 19:04:07 +04:00
}
2014-04-29 06:04:09 +04:00
2014-04-22 19:04:07 +04:00
/* 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
*/
2014-06-16 21:18:45 +04:00
2014-04-28 21:57:17 +04:00
if ( _comm_ioctl_tcsetattr ( pComm - > fd , TCSANOW , & upcomingTermios ) < 0 )
2014-04-22 19:04:07 +04:00
{
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
2014-06-16 21:18:45 +04:00
2014-04-02 23:51:28 +04:00
return TRUE ;
}
2014-05-12 19:33:56 +04:00
/**
* ERRORS :
* ERROR_INVALID_HANDLE
*/
2014-04-02 23:51:28 +04:00
BOOL GetCommTimeouts ( HANDLE hFile , LPCOMMTIMEOUTS lpCommTimeouts )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-05-12 19:33:56 +04:00
DWORD bytesReturned ;
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-05-12 19:33:56 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " GetCommTimeouts failure. " ) ;
2014-04-02 23:51:28 +04:00
return FALSE ;
2014-05-12 19:33:56 +04:00
}
2014-04-02 23:51:28 +04:00
return TRUE ;
}
2014-05-12 19:33:56 +04:00
/**
* ERRORS :
* ERROR_INVALID_HANDLE
*/
2014-04-02 23:51:28 +04:00
BOOL SetCommTimeouts ( HANDLE hFile , LPCOMMTIMEOUTS lpCommTimeouts )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-05-12 19:33:56 +04:00
DWORD bytesReturned ;
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-05-12 19:33:56 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommTimeouts failure. " ) ;
2014-04-02 23:51:28 +04:00
return FALSE ;
2014-05-12 19:33:56 +04:00
}
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL GetDefaultCommConfigA ( LPCSTR lpszName , LPCOMMCONFIG lpCC , LPDWORD lpdwSize )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL GetDefaultCommConfigW ( LPCWSTR lpszName , LPCOMMCONFIG lpCC , LPDWORD lpdwSize )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL SetDefaultCommConfigA ( LPCSTR lpszName , LPCOMMCONFIG lpCC , DWORD dwSize )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL SetDefaultCommConfigW ( LPCWSTR lpszName , LPCOMMCONFIG lpCC , DWORD dwSize )
{
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL SetCommBreak ( HANDLE hFile )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL ClearCommBreak ( HANDLE hFile )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL ClearCommError ( HANDLE hFile , PDWORD lpErrors , LPCOMSTAT lpStat )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
2014-05-14 23:21:31 +04:00
2014-04-02 23:51:28 +04:00
BOOL PurgeComm ( HANDLE hFile , DWORD dwFlags )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-05-14 23:21:31 +04:00
DWORD bytesReturned = 0 ;
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-05-14 23:21:31 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " PurgeComm failure. " ) ;
2014-04-02 23:51:28 +04:00
return FALSE ;
2014-05-14 23:21:31 +04:00
}
2014-04-02 23:51:28 +04:00
return TRUE ;
}
2014-05-14 23:21:31 +04:00
2014-04-02 23:51:28 +04:00
BOOL SetupComm ( HANDLE hFile , DWORD dwInQueue , DWORD dwOutQueue )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-05-14 19:30:29 +04:00
SERIAL_QUEUE_SIZE queueSize ;
DWORD bytesReturned = 0 ;
2014-04-02 23:51:28 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-05-14 19:30:29 +04:00
if ( ! pComm | | pComm - > Type ! = HANDLE_TYPE_COMM | | ! pComm - > fd )
{
SetLastError ( ERROR_INVALID_HANDLE ) ;
2014-04-02 23:51:28 +04:00
return FALSE ;
2014-05-14 19:30:29 +04:00
}
2014-04-02 23:51:28 +04:00
2014-05-14 19:30:29 +04:00
queueSize . InSize = dwInQueue ;
queueSize . OutSize = dwOutQueue ;
2014-04-22 19:04:07 +04:00
2014-05-14 19:30:29 +04:00
if ( ! CommDeviceIoControl ( pComm , IOCTL_SERIAL_SET_QUEUE_SIZE , & queueSize , sizeof ( SERIAL_QUEUE_SIZE ) , NULL , 0 , & bytesReturned , NULL ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " SetCommTimeouts failure. " ) ;
2014-05-14 19:30:29 +04:00
return FALSE ;
}
2014-04-22 19:04:07 +04:00
2014-04-02 23:51:28 +04:00
return TRUE ;
}
BOOL EscapeCommFunction ( HANDLE hFile , DWORD dwFunc )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL TransmitCommChar ( HANDLE hFile , char cChar )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
BOOL WaitCommEvent ( HANDLE hFile , PDWORD lpEvtMask , LPOVERLAPPED lpOverlapped )
{
WINPR_COMM * pComm = ( WINPR_COMM * ) hFile ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
/* TODO: not implemented */
2014-04-02 23:51:28 +04:00
if ( ! pComm )
return FALSE ;
return TRUE ;
}
2014-04-18 19:18:08 +04:00
/* Extended API */
static BOOL _IsReservedCommDeviceName ( LPCTSTR lpName )
{
int i ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-04-18 19:18:08 +04:00
/* Serial ports, COM1-9 */
for ( i = 1 ; i < 10 ; i + + )
{
TCHAR genericName [ 5 ] ;
2014-07-04 14:24:41 +04:00
if ( _stprintf_s ( genericName , 5 , _T ( " COM%d " ) , i ) < 0 )
2014-04-18 19:18:08 +04:00
{
return FALSE ;
}
if ( _tcscmp ( genericName , lpName ) = = 0 )
return TRUE ;
}
/* Parallel ports, LPT1-9 */
for ( i = 1 ; i < 10 ; i + + )
{
TCHAR genericName [ 5 ] ;
2014-07-04 14:24:41 +04:00
if ( _stprintf_s ( genericName , 5 , _T ( " LPT%d " ) , i ) < 0 )
2014-04-18 19:18:08 +04:00
{
return FALSE ;
}
if ( _tcscmp ( genericName , lpName ) = = 0 )
return TRUE ;
}
2014-05-27 13:33:10 +04:00
/* FIXME: what about PRN ? */
2014-04-18 19:18:08 +04:00
return FALSE ;
}
/**
* Returns TRUE on success , FALSE otherwise . To get extended error
* information , call GetLastError .
2014-06-16 21:18:45 +04:00
*
2014-04-18 19:18:08 +04:00
* ERRORS :
2014-06-19 14:03:36 +04:00
* ERROR_DLL_INIT_FAILED
2014-04-18 19:18:08 +04:00
* 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 )
{
2014-05-23 19:46:05 +04:00
int i = 0 ;
2014-04-18 19:18:08 +04:00
LPTSTR storedDeviceName = NULL ;
LPTSTR storedTargetPath = NULL ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
2014-07-03 13:07:48 +04:00
return FALSE ;
EnterCriticalSection ( & _CommDevicesLock ) ;
2014-06-19 14:03:36 +04:00
2014-04-18 19:18:08 +04:00
if ( _CommDevices = = NULL )
{
2014-06-19 14:03:36 +04:00
SetLastError ( ERROR_DLL_INIT_FAILED ) ;
2014-04-18 19:18:08 +04:00
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 ;
}
2014-05-23 19:46:05 +04:00
for ( i = 0 ; i < COMM_DEVICE_MAX ; i + + )
2014-04-18 19:18:08 +04:00
{
2014-05-23 19:46:05 +04:00
if ( _CommDevices [ i ] ! = NULL )
{
if ( _tcscmp ( _CommDevices [ i ] - > name , 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 ) ;
2014-04-18 19:18:08 +04:00
goto error_handle ;
}
2014-07-03 13:07:48 +04:00
LeaveCriticalSection ( & _CommDevicesLock ) ;
2014-04-18 19:18:08 +04:00
return TRUE ;
2015-05-11 10:07:39 +03:00
error_handle :
free ( storedDeviceName ) ;
free ( storedTargetPath ) ;
2014-04-18 19:18:08 +04:00
2014-07-03 13:07:48 +04:00
LeaveCriticalSection ( & _CommDevicesLock ) ;
2014-04-18 19:18:08 +04:00
return FALSE ;
}
/**
* Returns the number of target paths in the buffer pointed to by
2014-06-16 21:18:45 +04:00
* lpTargetPath .
2014-04-18 19:18:08 +04:00
*
* The current implementation returns in any case 0 and 1 target
* path . A NULL lpDeviceName is not supported yet to get all the
* paths .
2014-06-16 21:18:45 +04:00
*
2014-04-18 19:18:08 +04:00
* ERRORS :
* ERROR_SUCCESS
2014-06-19 14:03:36 +04:00
* ERROR_DLL_INIT_FAILED
2014-04-18 19:18:08 +04:00
* 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 )
{
2014-05-23 19:46:05 +04:00
int i ;
2014-04-18 19:18:08 +04:00
LPTSTR storedTargetPath ;
SetLastError ( ERROR_SUCCESS ) ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
2014-06-19 14:03:36 +04:00
return 0 ;
2014-04-18 19:18:08 +04:00
if ( _CommDevices = = NULL )
{
2014-06-19 14:03:36 +04:00
SetLastError ( ERROR_DLL_INIT_FAILED ) ;
2014-04-18 19:18:08 +04:00
return 0 ;
}
if ( lpDeviceName = = NULL | | lpTargetPath = = NULL )
{
SetLastError ( ERROR_NOT_SUPPORTED ) ;
return 0 ;
}
2014-07-03 13:07:48 +04:00
EnterCriticalSection ( & _CommDevicesLock ) ;
2014-05-23 19:46:05 +04:00
storedTargetPath = NULL ;
for ( i = 0 ; i < COMM_DEVICE_MAX ; i + + )
{
if ( _CommDevices [ i ] ! = NULL )
{
if ( _tcscmp ( _CommDevices [ i ] - > name , lpDeviceName ) = = 0 )
{
storedTargetPath = _CommDevices [ i ] - > path ;
break ;
}
continue ;
}
break ;
}
2014-06-16 21:18:45 +04:00
2014-07-03 13:07:48 +04:00
LeaveCriticalSection ( & _CommDevicesLock ) ;
2014-04-18 19:18:08 +04:00
if ( storedTargetPath = = NULL )
{
SetLastError ( ERROR_INVALID_DATA ) ;
return 0 ;
}
if ( _tcslen ( storedTargetPath ) + 2 > ucchMax )
{
SetLastError ( ERROR_INSUFFICIENT_BUFFER ) ;
return 0 ;
}
_tcscpy ( lpTargetPath , storedTargetPath ) ;
2014-07-04 14:24:41 +04:00
lpTargetPath [ _tcslen ( storedTargetPath ) + 1 ] = ' \0 ' ; /* 2nd final '\0' */
2014-04-18 19:18:08 +04:00
return _tcslen ( lpTargetPath ) + 2 ;
}
/**
2014-06-16 21:18:45 +04:00
* Checks whether lpDeviceName is a valid and registered Communication device .
2014-04-18 19:18:08 +04:00
*/
BOOL IsCommDevice ( LPCTSTR lpDeviceName )
{
TCHAR lpTargetPath [ MAX_PATH ] ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-04-18 19:18:08 +04:00
if ( QueryCommDevice ( lpDeviceName , lpTargetPath , MAX_PATH ) > 0 )
{
return TRUE ;
}
return FALSE ;
}
2014-04-29 00:32:27 +04:00
/**
2014-06-16 21:18:45 +04:00
* Sets
2014-04-29 00:32:27 +04:00
*/
2014-06-18 17:58:08 +04:00
void _comm_setServerSerialDriver ( HANDLE hComm , SERIAL_DRIVER_ID driverId )
2014-04-29 00:32:27 +04:00
{
ULONG Type ;
PVOID Object ;
WINPR_COMM * pComm ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return ;
2014-04-29 00:32:27 +04:00
if ( ! winpr_Handle_GetInfo ( hComm , & Type , & Object ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " _comm_setServerSerialDriver failure " ) ;
2014-04-29 00:32:27 +04:00
return ;
}
pComm = ( WINPR_COMM * ) Object ;
2014-06-18 17:58:08 +04:00
pComm - > serverSerialDriverId = driverId ;
2014-04-29 00:32:27 +04:00
}
2015-03-16 02:29:37 +03:00
static HANDLE_OPS ops = {
CommIsHandled ,
CommCloseHandle ,
CommGetFd ,
NULL /* CleanupHandle */
} ;
2014-04-29 00:32:27 +04:00
2014-04-22 19:04:07 +04:00
/**
* 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 .
2014-06-16 21:18:45 +04:00
*
2014-04-22 19:04:07 +04:00
* @ param lpSecurityAttributes NULL expected , a warning message is printed
* otherwise . TODO : better support .
2014-06-16 21:18:45 +04:00
*
2014-04-22 19:04:07 +04:00
* @ 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 .
*
2014-06-16 21:18:45 +04:00
* @ return INVALID_HANDLE_VALUE on error .
2014-04-22 19:04:07 +04:00
*/
HANDLE CommCreateFileA ( LPCSTR lpDeviceName , DWORD dwDesiredAccess , DWORD dwShareMode , LPSECURITY_ATTRIBUTES lpSecurityAttributes ,
2014-06-16 21:18:45 +04:00
DWORD dwCreationDisposition , DWORD dwFlagsAndAttributes , HANDLE hTemplateFile )
2014-04-18 19:18:08 +04:00
{
2014-04-22 19:04:07 +04:00
CHAR devicePath [ MAX_PATH ] ;
struct stat deviceStat ;
WINPR_COMM * pComm = NULL ;
2014-05-12 19:33:56 +04:00
struct termios upcomingTermios ;
2014-06-16 21:18:45 +04:00
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return INVALID_HANDLE_VALUE ;
2014-04-22 19:04:07 +04:00
if ( dwDesiredAccess ! = ( GENERIC_READ | GENERIC_WRITE ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " unexpected access to the device: 0x%lX " , dwDesiredAccess ) ;
2014-04-22 19:04:07 +04:00
}
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 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " unexpected security attributes, nLength=%lu " , lpSecurityAttributes - > nLength ) ;
2014-04-22 19:04:07 +04:00
}
if ( dwCreationDisposition ! = OPEN_EXISTING )
{
SetLastError ( ERROR_FILE_NOT_FOUND ) ; /* FIXME: ERROR_NOT_SUPPORTED better? */
return INVALID_HANDLE_VALUE ;
}
2014-06-16 21:18:45 +04:00
2014-04-22 19:04:07 +04:00
if ( QueryCommDevice ( lpDeviceName , devicePath , MAX_PATH ) < = 0 )
{
/* SetLastError(GetLastError()); */
return INVALID_HANDLE_VALUE ;
}
2014-04-18 19:18:08 +04:00
2014-04-22 19:04:07 +04:00
if ( stat ( devicePath , & deviceStat ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " device not found %s " , devicePath ) ;
2014-04-22 19:04:07 +04:00
SetLastError ( ERROR_FILE_NOT_FOUND ) ;
return INVALID_HANDLE_VALUE ;
}
if ( ! S_ISCHR ( deviceStat . st_mode ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " bad device %s " , devicePath ) ;
2014-04-22 19:04:07 +04:00
SetLastError ( ERROR_BAD_DEVICE ) ;
return INVALID_HANDLE_VALUE ;
}
if ( dwFlagsAndAttributes ! = 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " unexpected flags and attributes: 0x%lX " , dwFlagsAndAttributes ) ;
2014-04-22 19:04:07 +04:00
}
if ( hTemplateFile ! = NULL )
{
SetLastError ( ERROR_NOT_SUPPORTED ) ; /* FIXME: other proper error? */
return INVALID_HANDLE_VALUE ;
}
2014-04-18 19:18:08 +04:00
pComm = ( WINPR_COMM * ) calloc ( 1 , sizeof ( WINPR_COMM ) ) ;
2014-04-22 19:04:07 +04:00
if ( pComm = = NULL )
{
SetLastError ( ERROR_OUTOFMEMORY ) ;
return INVALID_HANDLE_VALUE ;
}
2014-04-18 19:18:08 +04:00
WINPR_HANDLE_SET_TYPE ( pComm , HANDLE_TYPE_COMM ) ;
2015-03-16 02:29:37 +03:00
pComm - > ops = & ops ;
2015-03-11 19:57:01 +03:00
2014-04-22 19:04:07 +04:00
/* error_handle */
pComm - > fd = open ( devicePath , O_RDWR | O_NOCTTY | O_NONBLOCK ) ;
if ( pComm - > fd < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " failed to open device %s " , devicePath ) ;
2014-04-22 19:04:07 +04:00
SetLastError ( ERROR_BAD_DEVICE ) ;
goto error_handle ;
}
2014-05-28 20:42:23 +04:00
pComm - > fd_read = open ( devicePath , O_RDONLY | O_NOCTTY | O_NONBLOCK ) ;
if ( pComm - > fd_read < 0 )
2014-05-12 19:33:56 +04:00
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " failed to open fd_read, device: %s " , devicePath ) ;
2014-05-12 19:33:56 +04:00
SetLastError ( ERROR_BAD_DEVICE ) ;
goto error_handle ;
}
2014-05-28 20:42:23 +04:00
pComm - > fd_read_event = eventfd ( 0 , EFD_NONBLOCK ) ; /* EFD_NONBLOCK required because a read() is not always expected */
if ( pComm - > fd_read_event < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " failed to open fd_read_event, device: %s " , devicePath ) ;
2014-05-28 20:42:23 +04:00
SetLastError ( ERROR_BAD_DEVICE ) ;
goto error_handle ;
}
2014-05-12 19:33:56 +04:00
2014-06-17 18:34:20 +04:00
InitializeCriticalSection ( & pComm - > ReadLock ) ;
2014-05-28 18:41:24 +04:00
pComm - > fd_write = open ( devicePath , O_WRONLY | O_NOCTTY | O_NONBLOCK ) ;
if ( pComm - > fd_write < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " failed to open fd_write, device: %s " , devicePath ) ;
2014-05-28 18:41:24 +04:00
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 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " failed to open fd_write_event, device: %s " , devicePath ) ;
2014-05-28 18:41:24 +04:00
SetLastError ( ERROR_BAD_DEVICE ) ;
goto error_handle ;
}
2014-06-17 18:34:20 +04:00
InitializeCriticalSection ( & pComm - > WriteLock ) ;
2014-06-18 20:20:21 +04:00
/* can also be setup later on with _comm_setServerSerialDriver() */
2014-06-18 17:58:08 +04:00
pComm - > serverSerialDriverId = SerialDriverUnknown ;
2014-05-12 19:33:56 +04:00
2014-05-27 14:29:24 +04:00
InitializeCriticalSection ( & pComm - > EventsLock ) ;
2014-05-14 18:29:10 +04:00
if ( ioctl ( pComm - > fd , TIOCGICOUNT , & ( pComm - > counters ) ) < 0 )
{
2014-11-13 21:54:32 +03:00
CommLog_Print ( WLOG_WARN , " TIOCGICOUNT ioctl failed, errno=[%d] %s. " , errno , strerror ( errno ) ) ;
CommLog_Print ( WLOG_WARN , " could not read counters. " ) ;
/* could not initialize counters but keep on.
*
* Not all drivers , especially for USB to serial
* adapters ( e . g . those based on pl2303 ) , does support
* this call .
*/
ZeroMemory ( & ( pComm - > counters ) , sizeof ( struct serial_icounter_struct ) ) ;
2014-05-14 18:29:10 +04:00
}
2014-05-12 19:33:56 +04:00
/* 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; */
2014-04-22 19:04:07 +04:00
2014-05-19 18:53:57 +04:00
/* About missing flags recommended by termios(3):
2014-05-12 19:33:56 +04:00
*
* IGNBRK and IXON , see : IOCTL_SERIAL_SET_HANDFLOW
* CSIZE , PARENB and CS8 , see : IOCTL_SERIAL_SET_LINE_CONTROL
2014-04-25 02:20:48 +04:00
*/
2014-06-16 21:18:45 +04:00
2014-05-12 19:33:56 +04:00
/* 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 ;
}
2014-04-25 02:20:48 +04:00
2014-04-22 19:04:07 +04:00
return ( HANDLE ) pComm ;
error_handle :
if ( pComm ! = NULL )
{
CloseHandle ( pComm ) ;
}
return INVALID_HANDLE_VALUE ;
2014-04-18 19:18:08 +04:00
}
2014-05-14 23:21:31 +04:00
2014-07-02 18:57:20 +04:00
BOOL CommIsHandled ( HANDLE handle )
{
WINPR_COMM * pComm ;
if ( ! CommInitialized ( ) )
return FALSE ;
pComm = ( WINPR_COMM * ) handle ;
2015-03-23 17:22:03 +03:00
if ( ! pComm | | ( pComm - > Type ! = HANDLE_TYPE_COMM ) | | ( pComm = = INVALID_HANDLE_VALUE ) )
2014-07-02 18:57:20 +04:00
{
SetLastError ( ERROR_INVALID_HANDLE ) ;
return FALSE ;
}
return TRUE ;
}
2014-06-19 21:07:45 +04:00
BOOL CommCloseHandle ( HANDLE handle )
{
WINPR_COMM * pComm ;
2014-07-02 17:59:16 +04:00
if ( ! CommInitialized ( ) )
return FALSE ;
2014-06-19 21:07:45 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " failure to WAIT_ON_MASK's loop! " ) ;
2014-06-19 21:07:45 +04:00
}
}
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 ;
}
2015-04-28 09:30:45 +03:00
# ifndef WITH_EVENTFD_READ_WRITE
2014-08-07 06:06:01 +04:00
int eventfd_read ( int fd , eventfd_t * value )
{
return ( read ( fd , value , sizeof ( * value ) ) = = sizeof ( * value ) ) ? 0 : - 1 ;
}
int eventfd_write ( int fd , eventfd_t value )
{
return ( write ( fd , & value , sizeof ( value ) ) = = sizeof ( value ) ) ? 0 : - 1 ;
}
# endif
2014-06-19 21:07:45 +04:00
2014-07-04 18:16:26 +04:00
# endif /* __linux__ */