2014-04-25 02:20:48 +04:00
/**
* WinPR : Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O . S . Systems Software Ltda .
* Copyright 2011 Eduardo Fiss Beloni < beloni @ ossystems . com . br >
* Copyright 2014 Marc - Andre Moreau < marcandre . moreau @ gmail . com >
* Copyright 2014 Hewlett - Packard Development Company , L . P .
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
2014-07-04 19:40:06 +04:00
# if defined __linux__ && !defined ANDROID
2014-04-28 21:57:17 +04:00
2014-05-12 22:33:33 +04:00
# include <assert.h>
2014-05-14 18:29:10 +04:00
# include <errno.h>
2014-05-14 23:21:31 +04:00
# include <fcntl.h>
2014-05-12 22:16:13 +04:00
# include <sys/ioctl.h>
2014-04-28 21:57:17 +04:00
# include <termios.h>
2014-05-27 13:33:10 +04:00
# include <unistd.h>
2014-04-28 21:57:17 +04:00
2014-04-25 02:20:48 +04:00
# include "comm_serial_sys.h"
2014-08-07 06:06:01 +04:00
# ifdef __UCLIBC__
# include "comm.h"
# endif
2014-04-25 02:20:48 +04:00
2014-04-28 21:57:17 +04:00
# include <winpr/crt.h>
2014-07-02 17:59:16 +04:00
# include <winpr/wlog.h>
2014-04-28 21:57:17 +04:00
2017-02-09 21:58:26 +03:00
/* Undocumented flag, not supported everywhere.
* Provide a sensible fallback to avoid compilation problems . */
# ifndef CMSPAR
# define CMSPAR 010000000000
# endif
2014-05-14 19:30:29 +04:00
/* 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
2014-09-16 13:21:01 +04:00
# define _BAUD_TABLE_END 0010020 /* __MAX_BAUD + 1 */
2014-05-14 19:30:29 +04:00
2014-09-16 13:21:01 +04:00
/* 0: B* (Linux termios)
* 1 : CBR_ * or actual baud rate
* 2 : BAUD_ * ( identical to SERIAL_BAUD_ * )
2014-04-28 21:57:17 +04:00
*/
2014-09-16 13:21:01 +04:00
static const speed_t _BAUD_TABLE [ ] [ 3 ] = {
2014-04-28 21:57:17 +04:00
# ifdef B0
2014-09-16 13:21:01 +04:00
{ B0 , 0 , 0 } , /* hang up */
# endif
# ifdef B50
{ B50 , 50 , 0 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B75
2014-09-16 13:21:01 +04:00
{ B75 , 75 , BAUD_075 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B110
2014-09-16 13:21:01 +04:00
{ B110 , CBR_110 , BAUD_110 } ,
# endif
# ifdef B134
{ B134 , 134 , 0 /*BAUD_134_5*/ } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B150
2014-09-16 13:21:01 +04:00
{ B150 , 150 , BAUD_150 } ,
# endif
# ifdef B200
{ B200 , 200 , 0 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B300
2014-09-16 13:21:01 +04:00
{ B300 , CBR_300 , BAUD_300 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B600
2014-09-16 13:21:01 +04:00
{ B600 , CBR_600 , BAUD_600 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B1200
2014-09-16 13:21:01 +04:00
{ B1200 , CBR_1200 , BAUD_1200 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B1800
2014-09-16 13:21:01 +04:00
{ B1800 , 1800 , BAUD_1800 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B2400
2014-09-16 13:21:01 +04:00
{ B2400 , CBR_2400 , BAUD_2400 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B4800
2014-09-16 13:21:01 +04:00
{ B4800 , CBR_4800 , BAUD_4800 } ,
2014-04-28 21:57:17 +04:00
# endif
2014-09-16 13:21:01 +04:00
/* {, ,BAUD_7200} */
2014-04-28 21:57:17 +04:00
# ifdef B9600
2014-09-16 13:21:01 +04:00
{ B9600 , CBR_9600 , BAUD_9600 } ,
2014-04-28 21:57:17 +04:00
# endif
2014-09-16 13:21:01 +04:00
/* {, CBR_14400, BAUD_14400}, /\* unsupported on Linux *\/ */
2014-04-28 21:57:17 +04:00
# ifdef B19200
2014-09-16 13:21:01 +04:00
{ B19200 , CBR_19200 , BAUD_19200 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B38400
2014-09-16 13:21:01 +04:00
{ B38400 , CBR_38400 , BAUD_38400 } ,
2014-04-28 21:57:17 +04:00
# endif
2014-09-16 13:21:01 +04:00
/* {, CBR_56000, BAUD_56K}, /\* unsupported on Linux *\/ */
2014-04-28 21:57:17 +04:00
# ifdef B57600
2014-09-16 13:21:01 +04:00
{ B57600 , CBR_57600 , BAUD_57600 } ,
2014-04-28 21:57:17 +04:00
# endif
# ifdef B115200
2014-09-16 13:21:01 +04:00
{ B115200 , CBR_115200 , BAUD_115200 } ,
2014-04-28 21:57:17 +04:00
# endif
2014-09-16 13:21:01 +04:00
/* {, 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
{ _BAUD_TABLE_END , 0 , 0 }
2014-04-28 21:57:17 +04:00
} ;
2014-05-14 18:29:10 +04:00
2014-04-28 21:57:17 +04:00
static BOOL _get_properties ( WINPR_COMM * pComm , COMMPROP * pProperties )
2014-04-25 02:20:48 +04:00
{
2014-04-28 21:57:17 +04:00
int i ;
2014-04-25 02:20:48 +04:00
2014-05-06 18:45:05 +04:00
/* 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
*/
2014-05-14 19:30:29 +04:00
/* FIXME: properties should be better probed. The current
2014-04-30 00:25:07 +04:00
* implementation just relies on the Linux ' implementation .
*/
2014-05-06 18:45:05 +04:00
if ( pProperties - > dwProvSpec1 ! = COMMPROP_INITIALIZED )
{
ZeroMemory ( pProperties , sizeof ( COMMPROP ) ) ;
pProperties - > wPacketLength = sizeof ( COMMPROP ) ;
}
pProperties - > wPacketVersion = 2 ;
2014-04-28 21:57:17 +04:00
2014-05-06 18:45:05 +04:00
pProperties - > dwServiceMask = SERIAL_SP_SERIALCOMM ;
/* pProperties->Reserved1; not used */
2014-05-14 19:30:29 +04:00
/* FIXME: could be implemented on top of N_TTY */
pProperties - > dwMaxTxQueue = N_TTY_BUF_SIZE ;
pProperties - > dwMaxRxQueue = N_TTY_BUF_SIZE ;
2014-05-06 18:45:05 +04:00
2014-09-16 13:21:01 +04:00
/* FIXME: to be probe on the device? */
pProperties - > dwMaxBaud = BAUD_USER ;
2014-05-06 18:08:58 +04:00
2014-05-28 13:39:10 +04:00
/* FIXME: what about PST_RS232? see also: serial_struct */
2014-05-06 18:08:58 +04:00
pProperties - > dwProvSubType = PST_UNSPECIFIED ;
2014-06-20 18:30:59 +04:00
/* TODO: to be finalized */
2014-06-16 21:18:45 +04:00
pProperties - > dwProvCapabilities =
2014-06-20 18:30:59 +04:00
/*PCF_16BITMODE |*/ PCF_DTRDSR | PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD |*/
PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS |*/ PCF_TOTALTIMEOUTS | PCF_XONXOFF ;
2014-05-06 18:08:58 +04:00
2014-06-20 18:30:59 +04:00
/* TODO: double check SP_RLSD */
2014-05-06 18:08:58 +04:00
pProperties - > dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY | SP_PARITY_CHECK | /*SP_RLSD |*/ SP_STOPBITS ;
2014-04-28 21:57:17 +04:00
pProperties - > dwSettableBaud = 0 ;
2014-09-16 13:21:01 +04:00
for ( i = 0 ; _BAUD_TABLE [ i ] [ 0 ] < _BAUD_TABLE_END ; i + + )
2014-04-28 21:57:17 +04:00
{
2014-09-16 13:21:01 +04:00
pProperties - > dwSettableBaud | = _BAUD_TABLE [ i ] [ 2 ] ;
2014-04-28 21:57:17 +04:00
}
2014-04-30 00:25:07 +04:00
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 ;
2014-05-28 13:39:10 +04:00
/* FIXME: additional input and output buffers could be implemented on top of N_TTY */
2014-05-14 19:30:29 +04:00
pProperties - > dwCurrentTxQueue = N_TTY_BUF_SIZE ;
pProperties - > dwCurrentRxQueue = N_TTY_BUF_SIZE ;
2014-05-06 18:45:05 +04:00
/* pProperties->ProvSpec1; see above */
/* pProperties->ProvSpec2; ignored */
/* pProperties->ProvChar[1]; ignored */
2014-04-28 21:57:17 +04:00
return TRUE ;
}
2014-04-29 06:04:09 +04:00
static BOOL _set_baud_rate ( WINPR_COMM * pComm , const SERIAL_BAUD_RATE * pBaudRate )
2014-04-28 21:57:17 +04:00
{
int i ;
speed_t newSpeed ;
2014-09-16 13:21:01 +04:00
struct termios futureState ;
2014-04-28 21:57:17 +04:00
2014-09-16 13:21:01 +04:00
ZeroMemory ( & futureState , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & futureState ) < 0 ) /* NB: preserves current settings not directly handled by the Communication Functions */
2014-04-28 21:57:17 +04:00
{
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
2014-09-16 13:21:01 +04:00
for ( i = 0 ; _BAUD_TABLE [ i ] [ 0 ] < _BAUD_TABLE_END ; i + + )
2014-04-28 21:57:17 +04:00
{
2014-09-16 13:21:01 +04:00
if ( _BAUD_TABLE [ i ] [ 1 ] = = pBaudRate - > BaudRate )
2014-04-28 21:57:17 +04:00
{
2014-09-16 13:21:01 +04:00
newSpeed = _BAUD_TABLE [ i ] [ 0 ] ;
if ( cfsetspeed ( & futureState , newSpeed ) < 0 )
2014-04-28 21:57:17 +04:00
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " failed to set speed 0x%x (% " PRIu32 " ) " , newSpeed , pBaudRate - > BaudRate ) ;
2014-04-28 21:57:17 +04:00
return FALSE ;
}
2014-09-16 13:21:01 +04:00
assert ( cfgetispeed ( & futureState ) = = newSpeed ) ;
if ( _comm_ioctl_tcsetattr ( pComm - > fd , TCSANOW , & futureState ) < 0 )
2014-04-28 21:57:17 +04:00
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " _comm_ioctl_tcsetattr failure: last-error: 0x% " PRIX32 " " , GetLastError ( ) ) ;
2014-04-28 21:57:17 +04:00
return FALSE ;
}
return TRUE ;
}
}
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " could not find a matching speed for the baud rate % " PRIu32 " " , pBaudRate - > BaudRate ) ;
2014-04-28 21:57:17 +04:00
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 ( & currentState , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & currentState ) < 0 )
{
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
currentSpeed = cfgetispeed ( & currentState ) ;
2014-09-16 13:21:01 +04:00
for ( i = 0 ; _BAUD_TABLE [ i ] [ 0 ] < _BAUD_TABLE_END ; i + + )
2014-04-28 21:57:17 +04:00
{
2014-09-16 13:21:01 +04:00
if ( _BAUD_TABLE [ i ] [ 0 ] = = currentSpeed )
2014-04-28 21:57:17 +04:00
{
2014-09-16 13:21:01 +04:00
pBaudRate - > BaudRate = _BAUD_TABLE [ i ] [ 1 ] ;
2014-04-28 21:57:17 +04:00
return TRUE ;
}
}
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " could not find a matching baud rate for the speed 0x%x " , currentSpeed ) ;
2014-04-28 21:57:17 +04:00
SetLastError ( ERROR_INVALID_DATA ) ;
2014-04-25 02:20:48 +04:00
return FALSE ;
}
2014-09-16 13:21:01 +04:00
2014-04-29 06:04:09 +04:00
/**
2014-05-06 18:08:58 +04:00
* NOTE : Only XonChar and XoffChar are plenty supported with the Linux
* N_TTY line discipline .
2014-04-29 06:04:09 +04:00
*
* ERRORS :
* ERROR_IO_DEVICE
* ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same ;
2014-05-06 18:08:58 +04:00
* ERROR_NOT_SUPPORTED
2014-04-29 06:04:09 +04:00
*/
static BOOL _set_serial_chars ( WINPR_COMM * pComm , const SERIAL_CHARS * pSerialChars )
{
2014-05-06 18:08:58 +04:00
BOOL result = TRUE ;
2014-04-29 06:04:09 +04:00
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 .
*
2014-05-06 18:08:58 +04:00
* 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
2014-04-29 06:04:09 +04:00
*/
2014-05-06 18:08:58 +04:00
if ( pSerialChars - > EofChar ! = ' \0 ' )
2014-04-29 06:04:09 +04:00
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " EofChar %02 " PRIX8 " cannot be set \n " , pSerialChars - > EofChar ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
2014-04-29 06:04:09 +04:00
}
/* According the Linux's n_tty discipline, charaters with a
* parity error can only be let unchanged , replaced by \ 0 or
2014-06-16 21:18:45 +04:00
* get the prefix the prefix \ 377 \ 0
2014-04-29 06:04:09 +04:00
*/
2014-05-06 18:08:58 +04:00
/* FIXME: see also: _set_handflow() */
if ( pSerialChars - > ErrorChar ! = ' \0 ' )
2014-04-29 06:04:09 +04:00
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " ErrorChar 0x%02 " PRIX8 " ('%c') cannot be set (unsupported). \n " , pSerialChars - > ErrorChar , ( char ) pSerialChars - > ErrorChar ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
2014-04-29 06:04:09 +04:00
}
2014-05-06 18:08:58 +04:00
/* FIXME: see also: _set_handflow() */
if ( pSerialChars - > BreakChar ! = ' \0 ' )
2014-04-29 06:04:09 +04:00
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " BreakChar 0x%02 " PRIX8 " ('%c') cannot be set (unsupported). \n " , pSerialChars - > BreakChar , ( char ) pSerialChars - > BreakChar ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
2014-04-29 06:04:09 +04:00
}
2014-06-20 18:30:59 +04:00
/* FIXME: could be implemented during read/write I/O. What about ISIG? */
2014-05-06 18:08:58 +04:00
if ( pSerialChars - > EventChar ! = ' \0 ' )
2014-04-29 06:04:09 +04:00
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " EventChar 0x%02 " PRIX8 " ('%c') cannot be set \n " , pSerialChars - > EventChar , ( char ) pSerialChars - > EventChar ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
2014-04-29 06:04:09 +04:00
}
upcomingTermios . c_cc [ VSTART ] = pSerialChars - > XonChar ;
upcomingTermios . c_cc [ VSTOP ] = pSerialChars - > XoffChar ;
if ( _comm_ioctl_tcsetattr ( pComm - > fd , TCSANOW , & upcomingTermios ) < 0 )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " _comm_ioctl_tcsetattr failure: last-error: 0x%08 " PRIX32 " " , GetLastError ( ) ) ;
2014-04-29 06:04:09 +04:00
return FALSE ;
}
2014-05-06 18:08:58 +04:00
return result ;
2014-04-29 06:04:09 +04:00
}
static BOOL _get_serial_chars ( WINPR_COMM * pComm , SERIAL_CHARS * pSerialChars )
{
struct termios currentTermios ;
ZeroMemory ( & currentTermios , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & currentTermios ) < 0 )
{
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
ZeroMemory ( pSerialChars , sizeof ( SERIAL_CHARS ) ) ;
2014-06-16 21:18:45 +04:00
2014-05-06 18:08:58 +04:00
/* EofChar unsupported */
2014-04-29 06:04:09 +04:00
2014-05-06 18:08:58 +04:00
/* ErrorChar unsupported */
/* BreakChar unsupported */
2014-06-16 21:18:45 +04:00
2014-06-20 18:30:59 +04:00
/* FIXME: see also: _set_serial_chars() */
2014-05-06 18:08:58 +04:00
/* EventChar */
2014-04-29 06:04:09 +04:00
pSerialChars - > XonChar = currentTermios . c_cc [ VSTART ] ;
pSerialChars - > XoffChar = currentTermios . c_cc [ VSTOP ] ;
return TRUE ;
}
2014-04-30 00:25:07 +04:00
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 :
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Unsupported one and a half stop bits. " ) ;
2014-04-30 00:25:07 +04:00
break ;
2014-06-16 21:18:45 +04:00
2014-04-30 00:25:07 +04:00
case STOP_BITS_2 :
upcomingTermios . c_cflag | = CSTOPB ;
break ;
default :
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " unexpected number of stop bits: % " PRIu8 " \n " , pLineControl - > StopBits ) ;
2014-04-30 00:25:07 +04:00
result = FALSE ; /* but keep on */
break ;
2014-06-16 21:18:45 +04:00
}
2014-04-30 00:25:07 +04:00
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 :
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " unexpected type of parity: % " PRIu8 " \n " , pLineControl - > Parity ) ;
2014-04-30 00:25:07 +04:00
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 :
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " unexpected number od data bits per character: % " PRIu8 " \n " , pLineControl - > WordLength ) ;
2014-04-30 00:25:07 +04:00
result = FALSE ; /* but keep on */
break ;
}
if ( _comm_ioctl_tcsetattr ( pComm - > fd , TCSANOW , & upcomingTermios ) < 0 )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " _comm_ioctl_tcsetattr failure: last-error: 0x%08 " PRIX32 " " , GetLastError ( ) ) ;
2014-04-30 00:25:07 +04:00
return FALSE ;
}
return result ;
}
static BOOL _get_line_control ( WINPR_COMM * pComm , SERIAL_LINE_CONTROL * pLineControl )
{
struct termios currentTermios ;
ZeroMemory ( & currentTermios , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & currentTermios ) < 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 ;
}
2014-05-06 18:08:58 +04:00
static BOOL _set_handflow ( WINPR_COMM * pComm , const SERIAL_HANDFLOW * pHandflow )
{
BOOL result = TRUE ;
struct termios upcomingTermios ;
ZeroMemory ( & upcomingTermios , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & upcomingTermios ) < 0 )
{
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
2014-05-19 18:53:57 +04:00
/* HUPCL */
/* logical XOR */
if ( ( ! ( pHandflow - > ControlHandShake & SERIAL_DTR_CONTROL ) & & ( pHandflow - > FlowReplace & SERIAL_RTS_CONTROL ) ) | |
2014-06-16 21:18:45 +04:00
( ( pHandflow - > ControlHandShake & SERIAL_DTR_CONTROL ) & & ! ( pHandflow - > FlowReplace & SERIAL_RTS_CONTROL ) ) )
2014-05-19 18:53:57 +04:00
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_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. " ,
2014-06-16 21:18:45 +04:00
( pHandflow - > ControlHandShake & SERIAL_DTR_CONTROL ) ? " ON " : " OFF " ,
( pHandflow - > FlowReplace & SERIAL_RTS_CONTROL ) ? " ON " : " OFF " ) ;
2014-05-19 18:53:57 +04:00
}
2014-05-06 18:08:58 +04:00
2014-05-19 18:53:57 +04:00
if ( ( pHandflow - > ControlHandShake & SERIAL_DTR_CONTROL ) | | ( pHandflow - > FlowReplace & SERIAL_RTS_CONTROL ) )
2014-05-06 18:08:58 +04:00
{
upcomingTermios . c_cflag | = HUPCL ;
}
else
{
upcomingTermios . c_cflag & = ~ HUPCL ;
2014-05-19 18:53:57 +04:00
/* 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? */
2014-05-06 18:08:58 +04:00
}
2014-05-19 18:53:57 +04:00
/* CRTSCTS */
/* logical XOR */
if ( ( ! ( pHandflow - > ControlHandShake & SERIAL_CTS_HANDSHAKE ) & & ( pHandflow - > FlowReplace & SERIAL_RTS_HANDSHAKE ) ) | |
2014-06-16 21:18:45 +04:00
( ( pHandflow - > ControlHandShake & SERIAL_CTS_HANDSHAKE ) & & ! ( pHandflow - > FlowReplace & SERIAL_RTS_HANDSHAKE ) ) )
2014-05-06 18:08:58 +04:00
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_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. " ,
2014-06-16 21:18:45 +04:00
( pHandflow - > ControlHandShake & SERIAL_CTS_HANDSHAKE ) ? " ON " : " OFF " ,
( pHandflow - > FlowReplace & SERIAL_RTS_HANDSHAKE ) ? " ON " : " OFF " ) ;
2014-05-06 18:08:58 +04:00
}
2014-05-19 18:53:57 +04:00
if ( ( pHandflow - > ControlHandShake & SERIAL_CTS_HANDSHAKE ) | | ( pHandflow - > FlowReplace & SERIAL_RTS_HANDSHAKE ) )
2014-05-06 18:08:58 +04:00
{
upcomingTermios . c_cflag | = CRTSCTS ;
}
else
{
upcomingTermios . c_cflag & = ~ CRTSCTS ;
}
2014-05-19 18:53:57 +04:00
/* ControlHandShake */
if ( pHandflow - > ControlHandShake & SERIAL_DTR_HANDSHAKE )
{
/* DTR/DSR flow control not supported on Linux */
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature. " ) ;
2014-05-19 18:53:57 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
}
2014-05-06 18:08:58 +04:00
if ( pHandflow - > ControlHandShake & SERIAL_DSR_HANDSHAKE )
{
/* DTR/DSR flow control not supported on Linux */
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature. " ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
}
if ( pHandflow - > ControlHandShake & SERIAL_DCD_HANDSHAKE )
{
/* DCD flow control not supported on Linux */
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_DCD_HANDSHAKE feature. " ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
}
2014-06-20 18:30:59 +04:00
// FIXME: could be implemented during read/write I/O
2014-05-06 18:08:58 +04:00
if ( pHandflow - > ControlHandShake & SERIAL_DSR_SENSITIVITY )
{
/* DSR line control not supported on Linux */
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_DSR_SENSITIVITY feature. " ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
}
2014-06-20 18:30:59 +04:00
// FIXME: could be implemented during read/write I/O
2014-05-06 18:08:58 +04:00
if ( pHandflow - > ControlHandShake & SERIAL_ERROR_ABORT )
{
/* Aborting operations on error not supported on Linux */
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_ERROR_ABORT feature. " ) ;
2014-05-06 18:08:58 +04:00
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 ;
}
2014-06-20 18:30:59 +04:00
// FIXME: could be implemented during read/write I/O, as of today ErrorChar is necessary '\0'
2014-05-06 18:08:58 +04:00
if ( pHandflow - > FlowReplace & SERIAL_ERROR_CHAR )
{
2014-05-19 18:53:57 +04:00
/* errors will be replaced by the character '\0'. */
2014-05-06 18:08:58 +04:00
upcomingTermios . c_iflag & = ~ IGNPAR ;
}
else
{
upcomingTermios . c_iflag | = IGNPAR ;
}
if ( pHandflow - > FlowReplace & SERIAL_NULL_STRIPPING )
{
upcomingTermios . c_iflag | = IGNBRK ;
}
else
{
upcomingTermios . c_iflag & = ~ IGNBRK ;
}
2014-06-20 18:30:59 +04:00
// FIXME: could be implemented during read/write I/O
2014-05-06 18:08:58 +04:00
if ( pHandflow - > FlowReplace & SERIAL_BREAK_CHAR )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_BREAK_CHAR feature. " ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
}
// FIXME: could be implemented during read/write I/O
if ( pHandflow - > FlowReplace & SERIAL_XOFF_CONTINUE )
{
/* not supported on Linux */
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " Attempt to use the unsupported SERIAL_XOFF_CONTINUE feature. " ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
result = FALSE ; /* but keep on */
}
/* XonLimit */
2014-06-16 21:18:45 +04:00
2014-05-06 18:08:58 +04:00
// FIXME: could be implemented during read/write I/O
if ( pHandflow - > XonLimit ! = TTY_THRESHOLD_UNTHROTTLE )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " Attempt to set XonLimit with an unsupported value: % " PRId32 " " , pHandflow - > XonLimit ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
2014-06-16 21:18:45 +04:00
result = FALSE ; /* but keep on */
2014-05-06 18:08:58 +04:00
}
/* XoffChar */
// FIXME: could be implemented during read/write I/O
if ( pHandflow - > XoffLimit ! = TTY_THRESHOLD_THROTTLE )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " Attempt to set XoffLimit with an unsupported value: % " PRId32 " " , pHandflow - > XoffLimit ) ;
2014-05-06 18:08:58 +04:00
SetLastError ( ERROR_NOT_SUPPORTED ) ;
2014-06-16 21:18:45 +04:00
result = FALSE ; /* but keep on */
2014-05-06 18:08:58 +04:00
}
if ( _comm_ioctl_tcsetattr ( pComm - > fd , TCSANOW , & upcomingTermios ) < 0 )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " _comm_ioctl_tcsetattr failure: last-error: 0x% " PRIX32 " " , GetLastError ( ) ) ;
2014-05-06 18:08:58 +04:00
return FALSE ;
}
return result ;
}
static BOOL _get_handflow ( WINPR_COMM * pComm , SERIAL_HANDFLOW * pHandflow )
{
struct termios currentTermios ;
ZeroMemory ( & currentTermios , sizeof ( struct termios ) ) ;
if ( tcgetattr ( pComm - > fd , & currentTermios ) < 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 */
2014-06-16 21:18:45 +04:00
2014-05-06 18:08:58 +04:00
if ( currentTermios . c_cflag & CRTSCTS )
pHandflow - > ControlHandShake | = SERIAL_CTS_HANDSHAKE ;
/* SERIAL_DSR_HANDSHAKE unsupported */
/* SERIAL_DCD_HANDSHAKE unsupported */
2014-06-16 21:18:45 +04:00
/* SERIAL_DSR_SENSITIVITY unsupported */
2014-05-06 18:08:58 +04:00
/* 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 ;
}
2014-05-12 19:33:56 +04:00
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 ) )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG " ) ;
2014-05-12 19:33:56 +04:00
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 ;
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_DEBUG , " ReadIntervalTimeout % " PRIu32 " " , pComm - > timeouts . ReadIntervalTimeout ) ;
CommLog_Print ( WLOG_DEBUG , " ReadTotalTimeoutMultiplier % " PRIu32 " " , pComm - > timeouts . ReadTotalTimeoutMultiplier ) ;
CommLog_Print ( WLOG_DEBUG , " ReadTotalTimeoutConstant % " PRIu32 " " , pComm - > timeouts . ReadTotalTimeoutConstant ) ;
CommLog_Print ( WLOG_DEBUG , " WriteTotalTimeoutMultiplier % " PRIu32 " " , pComm - > timeouts . WriteTotalTimeoutMultiplier ) ;
CommLog_Print ( WLOG_DEBUG , " WriteTotalTimeoutConstant % " PRIu32 " " , pComm - > timeouts . WriteTotalTimeoutConstant ) ;
2015-03-09 22:01:51 +03:00
2014-05-12 19:33:56 +04:00
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 ;
}
2014-04-25 02:20:48 +04:00
2014-05-14 18:29:10 +04:00
static BOOL _set_lines ( WINPR_COMM * pComm , UINT32 lines )
2014-05-12 22:16:13 +04:00
{
2014-05-14 18:29:10 +04:00
if ( ioctl ( pComm - > fd , TIOCMBIS , & lines ) < 0 )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " TIOCMBIS ioctl failed, lines=0x% " PRIX32 " , errno=[%d] %s " , lines , errno , strerror ( errno ) ) ;
2014-05-14 18:29:10 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
2014-05-12 22:16:13 +04:00
return TRUE ;
}
2014-05-14 18:29:10 +04:00
static BOOL _clear_lines ( WINPR_COMM * pComm , UINT32 lines )
2014-05-12 22:16:13 +04:00
{
2014-05-14 18:29:10 +04:00
if ( ioctl ( pComm - > fd , TIOCMBIC , & lines ) < 0 )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " TIOCMBIC ioctl failed, lines=0x% " PRIX32 " , errno=[%d] %s " , lines , errno , strerror ( errno ) ) ;
2014-05-14 18:29:10 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
2014-05-12 22:16:13 +04:00
return TRUE ;
}
static BOOL _set_dtr ( WINPR_COMM * pComm )
{
2014-05-12 22:33:33 +04:00
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 ;
}
2014-05-12 22:16:13 +04:00
2014-05-14 18:29:10 +04:00
return _set_lines ( pComm , TIOCM_DTR ) ;
2014-05-12 22:16:13 +04:00
}
static BOOL _clear_dtr ( WINPR_COMM * pComm )
{
2014-05-12 22:33:33 +04:00
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 ;
}
2014-05-12 22:16:13 +04:00
2014-05-14 18:29:10 +04:00
return _clear_lines ( pComm , TIOCM_DTR ) ;
2014-05-12 22:16:13 +04:00
}
2014-05-12 22:33:33 +04:00
static BOOL _set_rts ( WINPR_COMM * pComm )
{
2014-05-19 18:53:57 +04:00
SERIAL_HANDFLOW handflow ;
if ( ! _get_handflow ( pComm , & handflow ) )
return FALSE ;
2014-05-14 18:29:10 +04:00
2014-05-19 18:53:57 +04:00
if ( handflow . FlowReplace & SERIAL_RTS_HANDSHAKE )
{
SetLastError ( ERROR_INVALID_PARAMETER ) ;
return FALSE ;
}
2014-05-14 18:29:10 +04:00
return _set_lines ( pComm , TIOCM_RTS ) ;
2014-05-12 22:33:33 +04:00
}
static BOOL _clear_rts ( WINPR_COMM * pComm )
{
2014-05-19 18:53:57 +04:00
SERIAL_HANDFLOW handflow ;
if ( ! _get_handflow ( pComm , & handflow ) )
return FALSE ;
2014-05-14 18:29:10 +04:00
2014-05-19 18:53:57 +04:00
if ( handflow . FlowReplace & SERIAL_RTS_HANDSHAKE )
{
SetLastError ( ERROR_INVALID_PARAMETER ) ;
return FALSE ;
}
2014-05-14 18:29:10 +04:00
return _clear_lines ( pComm , TIOCM_RTS ) ;
2014-05-12 22:33:33 +04:00
}
2014-05-12 22:16:13 +04:00
2014-05-13 19:27:51 +04:00
static BOOL _get_modemstatus ( WINPR_COMM * pComm , ULONG * pRegister )
{
UINT32 lines = 0 ;
2014-05-14 18:29:10 +04:00
if ( ioctl ( pComm - > fd , TIOCMGET , & lines ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TIOCMGET ioctl failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-14 18:29:10 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
2014-05-13 19:27:51 +04:00
ZeroMemory ( pRegister , sizeof ( ULONG ) ) ;
2014-06-16 21:18:45 +04:00
2014-05-19 18:53:57 +04:00
/* FIXME: Is the last read of the MSR register available or
* cached somewhere ? Not quite sure we need to return the 4
2014-05-23 14:27:09 +04:00
* LSBits anyway . A direct access to the register - - which
* would reset the register - - is likely not expected from
* this function .
2014-05-13 19:27:51 +04:00
*/
/* #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 ;
}
2014-05-14 18:29:10 +04:00
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
2014-06-16 21:18:45 +04:00
static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK =
2014-05-14 18:29:10 +04:00
SERIAL_EV_RXCHAR |
SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
2014-06-16 21:18:45 +04:00
SERIAL_EV_DSR |
2014-05-14 18:29:10 +04:00
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 ;
2014-05-27 14:29:24 +04:00
2014-05-27 19:29:55 +04:00
/* 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 )
2014-05-27 18:17:47 +04:00
{
2014-05-27 19:29:55 +04:00
/* 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 */
2014-05-27 18:17:47 +04:00
}
2014-05-27 19:29:55 +04:00
/* NB: ensure to leave the critical section before to return */
EnterCriticalSection ( & pComm - > EventsLock ) ;
2014-05-14 18:29:10 +04:00
if ( * pWaitMask = = 0 )
{
/* clearing pending events */
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 ) ) ;
if ( pComm - > permissive )
{
/* counters could not be reset but keep on */
ZeroMemory ( & ( pComm - > counters ) , sizeof ( struct serial_icounter_struct ) ) ;
}
else
{
SetLastError ( ERROR_IO_DEVICE ) ;
LeaveCriticalSection ( & pComm - > EventsLock ) ;
return FALSE ;
}
2014-05-14 18:29:10 +04:00
}
2014-05-23 14:27:09 +04:00
pComm - > PendingEvents = 0 ;
2014-05-14 18:29:10 +04:00
}
2014-05-27 13:33:10 +04:00
2014-05-14 18:29:10 +04:00
possibleMask = * pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK ;
if ( possibleMask ! = * pWaitMask )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " Not all wait events supported (Serial.sys), requested events= 0x%08 " PRIX32 " , possible events= 0x%08 " PRIX32 " " , * pWaitMask , possibleMask ) ;
2014-05-14 18:29:10 +04:00
/* FIXME: shall we really set the possibleMask and return FALSE? */
2014-05-23 17:55:44 +04:00
pComm - > WaitEventMask = possibleMask ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-14 18:29:10 +04:00
return FALSE ;
}
2014-05-23 17:55:44 +04:00
pComm - > WaitEventMask = possibleMask ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-14 18:29:10 +04:00
return TRUE ;
}
static BOOL _get_wait_mask ( WINPR_COMM * pComm , ULONG * pWaitMask )
{
2014-05-23 17:55:44 +04:00
* pWaitMask = pComm - > WaitEventMask ;
2014-05-14 18:29:10 +04:00
return TRUE ;
}
2014-05-13 19:27:51 +04:00
2014-05-14 19:30:29 +04:00
static BOOL _set_queue_size ( WINPR_COMM * pComm , const SERIAL_QUEUE_SIZE * pQueueSize )
{
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 )
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " Requested an incompatible input buffer size: % " PRIu32 " , keeping on with a % " PRIu32 " bytes buffer. " , pQueueSize - > InSize , N_TTY_BUF_SIZE ) ;
2014-05-14 19:30:29 +04:00
if ( pQueueSize - > OutSize > N_TTY_BUF_SIZE )
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " Requested an incompatible output buffer size: % " PRIu32 " , keeping on with a % " PRIu32 " bytes buffer. " , pQueueSize - > OutSize , N_TTY_BUF_SIZE ) ;
2014-05-14 19:30:29 +04:00
SetLastError ( ERROR_CANCELLED ) ;
return FALSE ;
}
2014-05-14 23:21:31 +04:00
static BOOL _purge ( WINPR_COMM * pComm , const ULONG * pPurgeMask )
{
if ( ( * pPurgeMask & ~ ( SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR ) ) > 0 )
{
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " Invalid purge mask: 0x% " PRIX32 " \n " , * pPurgeMask ) ;
2014-05-14 23:21:31 +04:00
SetLastError ( ERROR_INVALID_PARAMETER ) ;
return FALSE ;
}
2014-06-16 21:18:45 +04:00
2014-05-28 18:41:24 +04:00
/* 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 ) */
2014-05-14 23:21:31 +04:00
2014-05-23 17:55:44 +04:00
if ( * pPurgeMask & SERIAL_PURGE_TXABORT )
{
/* Purges all write (IRP_MJ_WRITE) requests. */
2014-05-28 21:10:01 +04:00
if ( eventfd_write ( pComm - > fd_write_event , FREERDP_PURGE_TXABORT ) < 0 )
2014-05-28 18:41:24 +04:00
{
if ( errno ! = EAGAIN )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " eventfd_write failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-28 18:41:24 +04:00
}
assert ( errno = = EAGAIN ) ; /* no reader <=> no pending IRP_MJ_WRITE */
}
2014-05-23 17:55:44 +04:00
}
2014-05-14 23:21:31 +04:00
if ( * pPurgeMask & SERIAL_PURGE_RXABORT )
{
/* Purges all read (IRP_MJ_READ) requests. */
2014-05-28 21:10:01 +04:00
if ( eventfd_write ( pComm - > fd_read_event , FREERDP_PURGE_RXABORT ) < 0 )
2014-05-28 20:42:23 +04:00
{
if ( errno ! = EAGAIN )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " eventfd_write failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-28 20:42:23 +04:00
}
2014-06-16 21:18:45 +04:00
2014-05-28 20:42:23 +04:00
assert ( errno = = EAGAIN ) ; /* no reader <=> no pending IRP_MJ_READ */
}
2014-05-14 23:21:31 +04:00
}
if ( * pPurgeMask & SERIAL_PURGE_TXCLEAR )
{
/* Purges the transmit buffer, if one exists. */
2014-06-16 21:18:45 +04:00
2014-05-14 23:21:31 +04:00
if ( tcflush ( pComm - > fd , TCOFLUSH ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " tcflush(TCOFLUSH) failure, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-14 23:21:31 +04:00
SetLastError ( ERROR_CANCELLED ) ;
return FALSE ;
}
}
if ( * pPurgeMask & SERIAL_PURGE_RXCLEAR )
{
/* Purges the receive buffer, if one exists. */
if ( tcflush ( pComm - > fd , TCIFLUSH ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " tcflush(TCIFLUSH) failure, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-14 23:21:31 +04:00
SetLastError ( ERROR_CANCELLED ) ;
return FALSE ;
}
}
return TRUE ;
}
2014-05-23 14:27:09 +04:00
/* 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 */
2014-06-16 21:18:45 +04:00
struct serial_icounter_struct currentCounters ;
2014-05-23 14:27:09 +04:00
2014-05-27 14:29:24 +04:00
/* NB: ensure to leave the critical section before to return */
EnterCriticalSection ( & pComm - > EventsLock ) ;
2014-05-27 13:33:10 +04:00
2014-05-23 14:27:09 +04:00
ZeroMemory ( pCommstatus , sizeof ( SERIAL_STATUS ) ) ;
ZeroMemory ( & currentCounters , sizeof ( struct serial_icounter_struct ) ) ;
if ( ioctl ( pComm - > fd , TIOCGICOUNT , & currentCounters ) < 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 , " coult not read counters. " ) ;
if ( pComm - > permissive )
{
/* Errors and events based on counters could not be
* detected but keep on .
*/
ZeroMemory ( & currentCounters , sizeof ( struct serial_icounter_struct ) ) ;
}
else
{
SetLastError ( ERROR_IO_DEVICE ) ;
LeaveCriticalSection ( & pComm - > EventsLock ) ;
return FALSE ;
}
2014-05-23 14:27:09 +04:00
}
/* 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 ;
}
2014-05-28 12:44:52 +04:00
/* HoldReasons */
2014-06-16 21:18:45 +04:00
2014-05-28 12:44:52 +04:00
/* 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 */
2014-05-23 14:27:09 +04:00
/* AmountInInQueue */
if ( ioctl ( pComm - > fd , TIOCINQ , & ( pCommstatus - > AmountInInQueue ) ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TIOCINQ ioctl failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-23 14:27:09 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-23 14:27:09 +04:00
return FALSE ;
}
/* AmountInOutQueue */
if ( ioctl ( pComm - > fd , TIOCOUTQ , & ( pCommstatus - > AmountInOutQueue ) ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TIOCOUTQ ioctl failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-23 14:27:09 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-23 14:27:09 +04:00
return FALSE ;
}
/* BOOLEAN EofReceived; FIXME: once EofChar supported */
2014-06-20 18:30:59 +04:00
/* BOOLEAN WaitForImmediate; TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR fully supported */
2014-06-16 21:18:45 +04:00
2014-05-23 14:27:09 +04:00
/* 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 ...*/
2014-06-16 21:18:45 +04:00
( pCommstatus - > AmountInOutQueue = = 0 ) ) /* output bufer is now empty */
2014-05-23 14:27:09 +04:00
{
pComm - > PendingEvents | = SERIAL_EV_TXEMPTY ;
}
else
{
2014-05-27 13:33:10 +04:00
/* FIXME: "now empty" from the specs is ambiguous, need to track previous completed transmission? */
2014-05-23 14:27:09 +04:00
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
{
2016-02-22 19:01:43 +03:00
/* FIXME: "is 80 percent full" from the specs is ambiguous, need to track when it previously * occurred? */
2014-05-23 14:27:09 +04:00
pComm - > PendingEvents & = ~ SERIAL_EV_RX80FULL ;
}
pComm - > counters = currentCounters ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-27 13:33:10 +04:00
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 ;
}
2014-05-23 14:27:09 +04:00
return TRUE ;
}
2014-05-27 13:33:10 +04:00
2014-05-23 14:27:09 +04:00
static void _consume_event ( WINPR_COMM * pComm , ULONG * pOutputMask , ULONG event )
{
2014-05-23 17:55:44 +04:00
if ( ( pComm - > WaitEventMask & event ) & & ( pComm - > PendingEvents & event ) )
2014-05-23 14:27:09 +04:00
{
pComm - > PendingEvents & = ~ event ; /* consumed */
* pOutputMask | = event ;
}
}
2014-05-27 13:33:10 +04:00
/*
* NB : see also : _set_wait_mask ( )
*/
2014-05-23 14:27:09 +04:00
static BOOL _wait_on_mask ( WINPR_COMM * pComm , ULONG * pOutputMask )
{
assert ( * pOutputMask = = 0 ) ;
2014-05-27 19:29:55 +04:00
EnterCriticalSection ( & pComm - > EventsLock ) ;
pComm - > PendingEvents | = SERIAL_EV_FREERDP_WAITING ;
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-27 13:33:10 +04:00
while ( TRUE )
2014-05-23 14:27:09 +04:00
{
2014-05-27 14:29:24 +04:00
/* NB: EventsLock also used by _refresh_PendingEvents() */
2014-05-27 13:33:10 +04:00
if ( ! _refresh_PendingEvents ( pComm ) )
2014-05-23 14:27:09 +04:00
{
2014-05-27 19:29:55 +04:00
EnterCriticalSection ( & pComm - > EventsLock ) ;
pComm - > PendingEvents & = ~ SERIAL_EV_FREERDP_WAITING ;
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-23 14:27:09 +04:00
return FALSE ;
}
2014-05-27 14:29:24 +04:00
/* NB: ensure to leave the critical section before to return */
EnterCriticalSection ( & pComm - > EventsLock ) ;
2014-06-16 21:18:45 +04:00
2014-05-27 14:29:24 +04:00
if ( pComm - > PendingEvents & SERIAL_EV_FREERDP_STOP )
{
pComm - > PendingEvents & = ~ SERIAL_EV_FREERDP_STOP ;
2014-05-23 14:27:09 +04:00
2014-05-27 14:29:24 +04:00
/* 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 ) ;
2014-05-27 19:29:55 +04:00
pComm - > PendingEvents & = ~ SERIAL_EV_FREERDP_WAITING ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
return TRUE ;
}
2014-05-27 13:33:10 +04:00
2014-05-23 14:27:09 +04:00
_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 ) ;
2014-05-27 14:29:24 +04:00
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-27 13:33:10 +04:00
/* NOTE: PendingEvents can be modified from now on but
* not pOutputMask */
2014-05-23 14:27:09 +04:00
if ( * pOutputMask ! = 0 )
{
/* at least an event occurred */
2014-05-27 19:29:55 +04:00
EnterCriticalSection ( & pComm - > EventsLock ) ;
pComm - > PendingEvents & = ~ SERIAL_EV_FREERDP_WAITING ;
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-23 14:27:09 +04:00
return TRUE ;
}
2014-05-27 13:33:10 +04:00
2014-05-27 14:29:24 +04:00
/* 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 .
*/
2014-05-27 13:33:10 +04:00
2014-05-27 14:29:24 +04:00
Sleep ( 100 ) ; /* 100 ms */
2014-05-23 14:27:09 +04:00
}
2016-12-14 00:47:08 +03:00
CommLog_Print ( WLOG_WARN , " _wait_on_mask, unexpected return, WaitEventMask=0x%08 " PRIX32 " " , pComm - > WaitEventMask ) ;
2014-05-27 19:29:55 +04:00
EnterCriticalSection ( & pComm - > EventsLock ) ;
pComm - > PendingEvents & = ~ SERIAL_EV_FREERDP_WAITING ;
LeaveCriticalSection ( & pComm - > EventsLock ) ;
2014-05-27 13:33:10 +04:00
assert ( FALSE ) ;
2014-05-23 14:27:09 +04:00
return FALSE ;
}
static BOOL _set_break_on ( WINPR_COMM * pComm )
{
if ( ioctl ( pComm - > fd , TIOCSBRK , NULL ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TIOCSBRK ioctl failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-23 14:27:09 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
return TRUE ;
}
2014-06-16 21:18:45 +04:00
2014-05-23 14:27:09 +04:00
static BOOL _set_break_off ( WINPR_COMM * pComm )
{
if ( ioctl ( pComm - > fd , TIOCCBRK , NULL ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TIOCSBRK ioctl failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-23 14:27:09 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
return TRUE ;
}
2014-05-14 23:21:31 +04:00
2014-05-23 15:04:43 +04:00
static BOOL _set_xoff ( WINPR_COMM * pComm )
{
if ( tcflow ( pComm - > fd , TCIOFF ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TCIOFF failure, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-23 15:04:43 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
return TRUE ;
}
static BOOL _set_xon ( WINPR_COMM * pComm )
{
if ( tcflow ( pComm - > fd , TCION ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TCION failure, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-23 15:04:43 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
return TRUE ;
}
2014-05-28 13:39:10 +04:00
BOOL _get_dtrrts ( WINPR_COMM * pComm , ULONG * pMask )
{
UINT32 lines = 0 ;
if ( ioctl ( pComm - > fd , TIOCMGET , & lines ) < 0 )
{
2014-07-02 17:59:16 +04:00
CommLog_Print ( WLOG_WARN , " TIOCMGET ioctl failed, errno=[%d] %s " , errno , strerror ( errno ) ) ;
2014-05-28 13:39:10 +04:00
SetLastError ( ERROR_IO_DEVICE ) ;
return FALSE ;
}
* pMask = 0 ;
2014-06-16 21:18:45 +04:00
2014-05-28 13:39:10 +04:00
if ( ! ( lines & TIOCM_DTR ) )
* pMask | = SERIAL_DTR_STATE ;
if ( ! ( lines & TIOCM_RTS ) )
* pMask | = SERIAL_RTS_STATE ;
2014-06-16 21:18:45 +04:00
2014-05-28 13:39:10 +04:00
return TRUE ;
}
2014-06-17 17:19:16 +04:00
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 ;
}
2014-06-17 18:34:20 +04:00
BOOL _immediate_char ( WINPR_COMM * pComm , const UCHAR * pChar )
{
BOOL result ;
DWORD nbBytesWritten = - 1 ;
2014-06-20 18:30:59 +04:00
/* FIXME: CommWriteFile uses a critical section, shall it be
* interrupted ?
*
* FIXME : see also _get_commstatus ( ) ' s WaitForImmediate boolean
*/
2014-06-17 18:34:20 +04:00
result = CommWriteFile ( pComm , pChar , 1 , & nbBytesWritten , NULL ) ;
assert ( nbBytesWritten = = 1 ) ;
return result ;
}
2014-06-17 19:49:06 +04:00
BOOL _reset_device ( WINPR_COMM * pComm )
{
/* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx */
return TRUE ;
}
2014-06-18 17:58:08 +04:00
static SERIAL_DRIVER _SerialSys =
2014-04-25 02:20:48 +04:00
{
2014-06-18 17:58:08 +04:00
. id = SerialDriverSerialSys ,
2014-04-29 06:04:09 +04:00
. 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 ,
2014-04-30 00:25:07 +04:00
. set_line_control = _set_line_control ,
2014-05-06 18:08:58 +04:00
. get_line_control = _get_line_control ,
. set_handflow = _set_handflow ,
. get_handflow = _get_handflow ,
2014-05-12 19:33:56 +04:00
. set_timeouts = _set_timeouts ,
. get_timeouts = _get_timeouts ,
2014-05-12 22:16:13 +04:00
. set_dtr = _set_dtr ,
. clear_dtr = _clear_dtr ,
2014-05-12 22:33:33 +04:00
. set_rts = _set_rts ,
. clear_rts = _clear_rts ,
2014-05-13 19:27:51 +04:00
. get_modemstatus = _get_modemstatus ,
2014-05-14 18:29:10 +04:00
. set_wait_mask = _set_wait_mask ,
. get_wait_mask = _get_wait_mask ,
. wait_on_mask = _wait_on_mask ,
2014-05-14 19:30:29 +04:00
. set_queue_size = _set_queue_size ,
2014-05-14 23:21:31 +04:00
. purge = _purge ,
2014-05-23 14:27:09 +04:00
. get_commstatus = _get_commstatus ,
. set_break_on = _set_break_on ,
. set_break_off = _set_break_off ,
2014-05-23 15:04:43 +04:00
. set_xoff = _set_xoff ,
. set_xon = _set_xon ,
2014-05-28 13:39:10 +04:00
. get_dtrrts = _get_dtrrts ,
2014-06-17 17:19:16 +04:00
. config_size = _config_size ,
2014-06-17 18:34:20 +04:00
. immediate_char = _immediate_char ,
2014-06-17 19:49:06 +04:00
. reset_device = _reset_device ,
2014-04-25 02:20:48 +04:00
} ;
2014-06-18 17:58:08 +04:00
SERIAL_DRIVER * SerialSys_s ( )
2014-04-25 02:20:48 +04:00
{
return & _SerialSys ;
}
2014-04-28 21:57:17 +04:00
2014-07-04 18:16:26 +04:00
# endif /* __linux__ */