winpr-comm: got IOCTL_SERIAL_GET_BAUD_RATE and IOCTL_SERIAL_GET_PROPERTIES (partial)

winpr-comm: cleant up unit tests
This commit is contained in:
Emmanuel Ledoux 2014-04-28 19:57:17 +02:00
parent e7f0185e69
commit 69eeeebe67
13 changed files with 721 additions and 316 deletions

View File

@ -33,9 +33,9 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-comm)
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-comm)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -4,6 +4,7 @@
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -41,6 +41,9 @@
#include <winpr/collections.h>
#include <winpr/tchar.h>
#include "comm_ioctl.h"
/**
* Communication Resources:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363196/
@ -139,159 +142,6 @@ BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp)
}
/*
* Linux, Windows speeds
*
*/
static const speed_t _SPEED_TABLE[][2] = {
#ifdef B0
{B0, 0}, /* hang up */
#endif
#ifdef B50
{B50, 50},
#endif
#ifdef B75
{B75, 75},
#endif
#ifdef B110
{B110, CBR_110},
#endif
#ifdef B134
{B134, 134},
#endif
#ifdef B150
{B150, 150},
#endif
#ifdef B200
{B200, 200},
#endif
#ifdef B300
{B300, CBR_300},
#endif
#ifdef B600
{B600, CBR_600},
#endif
#ifdef B1200
{B1200, CBR_1200},
#endif
#ifdef B1800
{B1800, 1800},
#endif
#ifdef B2400
{B2400, CBR_2400},
#endif
#ifdef B4800
{B4800, CBR_4800},
#endif
#ifdef B9600
{B9600, CBR_9600},
#endif
/* {, CBR_14400}, /\* unsupported on Linux *\/ */
#ifdef B19200
{B19200, CBR_19200},
#endif
#ifdef B38400
{B38400, CBR_38400},
#endif
/* {, CBR_56000}, /\* unsupported on Linux *\/ */
#ifdef B57600
{B57600, CBR_57600},
#endif
#ifdef B115200
{B115200, CBR_115200},
#endif
/* {, CBR_128000}, /\* unsupported on Linux *\/ */
/* {, CBR_256000}, /\* unsupported on Linux *\/ */
#ifdef B230400
{B230400, 230400},
#endif
#ifdef B460800
{B460800, 460800},
#endif
#ifdef B500000
{B500000, 500000},
#endif
#ifdef B576000
{B576000, 576000},
#endif
#ifdef B921600
{B921600, 921600},
#endif
#ifdef B1000000
{B1000000, 1000000},
#endif
#ifdef B1152000
{B1152000, 1152000},
#endif
#ifdef B1500000
{B1500000, 1500000},
#endif
#ifdef B2000000
{B2000000, 2000000},
#endif
#ifdef B2500000
{B2500000, 2500000},
#endif
#ifdef B3000000
{B3000000, 3000000},
#endif
#ifdef B3500000
{B3500000, 3500000},
#endif
#ifdef B4000000
{B4000000, 4000000}, /* __MAX_BAUD */
#endif
};
/* Set lpDcb->BaudRate with the current baud rate.
*/
static BOOL _GetBaudRate(LPDCB lpDcb, struct termios *lpCurrentState)
{
int i;
speed_t currentSpeed;
currentSpeed = cfgetispeed(lpCurrentState);
for (i=0; _SPEED_TABLE[i][0]<=__MAX_BAUD; i++)
{
if (_SPEED_TABLE[i][0] == currentSpeed)
{
lpDcb->BaudRate = _SPEED_TABLE[i][1];
return TRUE;
}
}
DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed);
return FALSE;
}
/* Set lpFutureState's speed to lpDcb->BaudRate.
*/
static BOOL _SetBaudRate(struct termios *lpFutureState, LPDCB lpDcb)
{
int i;
speed_t newSpeed;
for (i=0; _SPEED_TABLE[i][0]<=__MAX_BAUD; i++)
{
if (_SPEED_TABLE[i][1] == lpDcb->BaudRate)
{
newSpeed = _SPEED_TABLE[i][0];
if (cfsetspeed(lpFutureState, newSpeed) < 0)
{
DEBUG_WARN("failed to set speed 0x%x (%d)", newSpeed, lpDcb->BaudRate);
return FALSE;
}
return TRUE;
}
}
DEBUG_WARN("could not find a matching speed for the baud rate %d", lpDcb->BaudRate);
return FALSE;
}
/**
*
@ -307,6 +157,7 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB)
DCB *lpLocalDcb;
struct termios currentState;
WINPR_COMM* pComm = (WINPR_COMM*) hFile;
DWORD bytesReturned;
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
{
@ -343,12 +194,14 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB)
lpLocalDcb->DCBlength = lpDCB->DCBlength;
if (!_GetBaudRate(lpLocalDcb, &currentState))
SERIAL_BAUD_RATE baudRate;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &baudRate, sizeof(SERIAL_BAUD_RATE), &bytesReturned, NULL))
{
SetLastError(ERROR_NOT_SUPPORTED);
DEBUG_WARN("GetCommState failure: could not get the baud rate.");
goto error_handle;
}
lpLocalDcb->BaudRate = baudRate.BaudRate;
lpLocalDcb->fBinary = TRUE; /* TMP: TODO: seems equivalent to the raw mode */
lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0;
@ -368,15 +221,23 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB)
/**
* @return TRUE on success, FALSE otherwise.
*
* As of today, SetCommState() can fail half-way with some settings
* applied and some others not. SetCommState() returns on the first
* failure met. FIXME: or is it correct?
*
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_IO_DEVICE
*/
BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
{
struct termios futureState;
struct termios currentState;
struct termios upcomingTermios;
WINPR_COMM* pComm = (WINPR_COMM*) hFile;
DWORD bytesReturned;
// TMP: FIXME: validate changes according GetCommProperties
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
{
@ -390,16 +251,28 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
return FALSE;
}
ZeroMemory(&futureState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */
/* NB: did the choice to call ioctls first when available and
then to setup upcomingTermios. Don't mix both stages. */
/** ioctl calls stage **/
SERIAL_BAUD_RATE baudRate;
baudRate.BaudRate = lpDCB->BaudRate;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate, sizeof(SERIAL_BAUD_RATE), NULL, 0, &bytesReturned, NULL))
{
SetLastError(ERROR_IO_DEVICE);
DEBUG_WARN("SetCommState failure: could not set the baud rate.");
return FALSE;
}
if (!_SetBaudRate(&futureState, lpDCB))
/** upcomingTermios stage **/
ZeroMemory(&upcomingTermios, sizeof(struct termios));
if (tcgetattr(pComm->fd, &upcomingTermios) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */
{
SetLastError(ERROR_NOT_SUPPORTED);
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
@ -413,16 +286,13 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
if (lpDCB->fParity)
{
futureState.c_iflag |= INPCK;
upcomingTermios.c_iflag |= INPCK;
}
else
{
futureState.c_iflag &= ~INPCK;
upcomingTermios.c_iflag &= ~INPCK;
}
// TMP: FIXME: validate changes according GetCommProperties
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx
*
* The SetCommState function reconfigures the communications
@ -434,43 +304,12 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
* TCSANOW matches the best this definition
*/
if (tcsetattr(pComm->fd, TCSANOW, &futureState) < 0)
{
DEBUG_WARN("could not apply parameters, errno: %d", errno);
return FALSE;
}
/* NB: tcsetattr() can succeed even if not all changes have been applied. */
ZeroMemory(&currentState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentState) < 0)
if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
if (memcmp(&currentState, &futureState, sizeof(struct termios)) != 0)
{
DEBUG_WARN("all parameters were not set, doing a second attempt...");
if (tcsetattr(pComm->fd, TCSAFLUSH, &futureState) < 0)
{
DEBUG_WARN("could not apply parameters, errno: %d", errno);
return FALSE;
}
ZeroMemory(&currentState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentState) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
if (memcmp(&currentState, &futureState, sizeof(struct termios)) != 0)
{
DEBUG_WARN("Failure: all parameters were not set on a second attempt.");
SetLastError(ERROR_IO_DEVICE);
return FALSE; /* TMP: double-check whether some parameters can differ anyway */
}
}
return TRUE;
}

View File

@ -26,7 +26,9 @@
#ifndef _WIN32
#include <assert.h>
#include <errno.h>
#include <freerdp/utils/debug.h>
@ -67,7 +69,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
PREMOTE_SERIAL_DRIVER pRemoteSerialDriver = NULL;
REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL;
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
{
@ -87,27 +89,30 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
return FALSE;
}
*lpBytesReturned = 0; /* will be ajusted otherwise */
*lpBytesReturned = 0; /* will be ajusted if required ... */
/* remoteSerialDriver to be use ... */
/* remoteSerialDriver to be use ...
*
* FIXME: might prefer to use an automatic rather than static structure
*/
switch (pComm->remoteSerialDriverId)
{
case RemoteSerialDriverSerialSys:
pRemoteSerialDriver = SerialSys();
pRemoteSerialDriver = SerialSys_s();
break;
case RemoteSerialDriverSerCxSys:
pRemoteSerialDriver = SerCxSys();
pRemoteSerialDriver = SerCxSys_s();
break;
case RemoteSerialDriverSerCx2Sys:
pRemoteSerialDriver = SerCx2Sys();
pRemoteSerialDriver = SerCx2Sys_s();
break;
case RemoteSerialDriverUnknown:
default:
DEBUG_WARN("Unknown remote serial driver (%d), using SerCx2.sys", pComm->remoteSerialDriverId);
pRemoteSerialDriver = SerCx2Sys();
pRemoteSerialDriver = SerCx2Sys_s();
break;
}
@ -117,84 +122,112 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
{
case IOCTL_SERIAL_SET_BAUD_RATE:
{
PSERIAL_BAUD_RATE pBaudRate = (PSERIAL_BAUD_RATE)lpInBuffer;
assert(nInBufferSize == sizeof(SERIAL_BAUD_RATE));
if (nInBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
if (pRemoteSerialDriver->set_baud_rate)
{
return pRemoteSerialDriver->set_baud_rate(pBaudRate);
}
else
{
DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name);
return FALSE;
SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_BAUD_RATE));
if (nInBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
return pRemoteSerialDriver->set_baud_rate(pComm, pBaudRate);
}
}
case IOCTL_SERIAL_GET_BAUD_RATE:
{
if (pRemoteSerialDriver->get_baud_rate)
{
SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE));
if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pRemoteSerialDriver->get_baud_rate(pComm, pBaudRate))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_BAUD_RATE);
return TRUE;
}
}
case IOCTL_SERIAL_GET_PROPERTIES:
{
if (pRemoteSerialDriver->get_properties)
{
COMMPROP *pProperties = (COMMPROP*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(COMMPROP));
if (nOutBufferSize < sizeof(COMMPROP))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pRemoteSerialDriver->get_properties(pComm, pProperties))
return FALSE;
*lpBytesReturned = sizeof(COMMPROP);
return TRUE;
}
}
default:
DEBUG_WARN("unsupported IoControlCode: Ox%x", dwIoControlCode);
return FALSE;
}
DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name);
return FALSE;
}
/* IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 */
/* IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C */
/* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */
/* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */
/* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */
/* IOCTL_SERIAL_SET_CHARS 0x001B0058 */
/* IOCTL_SERIAL_GET_CHARS 0x001B005C */
/* IOCTL_SERIAL_SET_DTR 0x001B0024 */
/* IOCTL_SERIAL_CLR_DTR 0x001B0028 */
/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */
/* IOCTL_SERIAL_SET_RTS 0x001B0030 */
/* IOCTL_SERIAL_CLR_RTS 0x001B0034 */
/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */
/* IOCTL_SERIAL_SET_XON 0x001B003C */
/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */
/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */
/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */
/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */
/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */
/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */
/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */
/* IOCTL_SERIAL_PURGE 0x001B004C */
/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */
/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */
/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */
/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */
/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */
/* IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 */
/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */
/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */
/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */
/* IOCTL_SERIAL_GET_STATS 0x001B008C */
/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */
/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */
/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */
/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */
int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
{
int result;
struct termios currentState;
/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */
/* IOCTL_PAR_SET_INFORMATION 0x00160008 */
/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */
/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */
/* IOCTL_IEEE1284_GET_MODE 0x00160014 */
/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */
/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */
/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */
/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */
/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */
/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */
/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */
return TRUE;
if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
{
DEBUG_WARN("tcsetattr failure, errno: %d", errno);
return result;
}
/* NB: tcsetattr() can succeed even if not all changes have been applied. */
ZeroMemory(&currentState, sizeof(struct termios));
if ((result = tcgetattr(fd, &currentState)) < 0)
{
DEBUG_WARN("tcgetattr failure, errno: %d", errno);
return result;
}
if (memcmp(&currentState, &termios_p, sizeof(struct termios)) != 0)
{
DEBUG_WARN("all termios parameters were not set, doing a second attempt...");
if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
{
DEBUG_WARN("2nd tcsetattr failure, errno: %d", errno);
return result;
}
ZeroMemory(&currentState, sizeof(struct termios));
if ((result = tcgetattr(fd, &currentState)) < 0)
{
DEBUG_WARN("tcgetattr failure, errno: %d", errno);
return result;
}
if (memcmp(&currentState, termios_p, sizeof(struct termios)) != 0)
{
DEBUG_WARN("Failure: all parameters were not set on a second attempt.");
return -1; /* TMP: double-check whether some parameters can differ anyway */
}
}
return 0;
}
#endif /* _WIN32 */

View File

@ -24,6 +24,8 @@
#ifndef _WIN32
#include <termios.h>
#include <winpr/io.h>
#include <winpr/tchar.h>
#include <winpr/wtypes.h>
@ -39,7 +41,57 @@ extern "C" {
#endif
#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004
#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004
#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050
/* #define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C */
/* IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 */
/* IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C */
/* IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 */
/* IOCTL_SERIAL_SET_CHARS 0x001B0058 */
/* IOCTL_SERIAL_GET_CHARS 0x001B005C */
/* IOCTL_SERIAL_SET_DTR 0x001B0024 */
/* IOCTL_SERIAL_CLR_DTR 0x001B0028 */
/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */
/* IOCTL_SERIAL_SET_RTS 0x001B0030 */
/* IOCTL_SERIAL_CLR_RTS 0x001B0034 */
/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */
/* IOCTL_SERIAL_SET_XON 0x001B003C */
/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */
/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */
/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */
/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */
/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */
/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */
/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */
/* IOCTL_SERIAL_PURGE 0x001B004C */
/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */
/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */
/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */
/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */
/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */
#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074
/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */
/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */
/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */
/* IOCTL_SERIAL_GET_STATS 0x001B008C */
/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */
/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */
/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */
/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */
/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */
/* IOCTL_PAR_SET_INFORMATION 0x00160008 */
/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */
/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */
/* IOCTL_IEEE1284_GET_MODE 0x00160014 */
/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */
/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */
/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */
/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */
/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */
/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */
/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */
@ -58,11 +110,14 @@ typedef struct _REMOTE_SERIAL_DRIVER
{
REMOTE_SERIAL_DRIVER_ID id;
TCHAR *name;
BOOL (*set_baud_rate)(PSERIAL_BAUD_RATE pBaudRate);
BOOL (*set_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate /* in */);
BOOL (*get_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate /* out */);
BOOL (*get_properties)(WINPR_COMM *pComm, COMMPROP *pProperties /* out */);
} REMOTE_SERIAL_DRIVER, *PREMOTE_SERIAL_DRIVER;
} REMOTE_SERIAL_DRIVER;
int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
#ifdef __cplusplus
}

View File

@ -20,26 +20,35 @@
* limitations under the License.
*/
#ifndef _WIN32
#include "comm_sercx_sys.h"
#include "comm_sercx2_sys.h"
#include "comm_serial_sys.h"
/* specific functions only */
static REMOTE_SERIAL_DRIVER _SerCx2Sys =
{
{
.id = RemoteSerialDriverSerCx2Sys,
.name = _T("SerCx2.sys"),
.set_baud_rate = NULL,
.get_baud_rate = NULL,
.get_properties = NULL,
};
PREMOTE_SERIAL_DRIVER SerCx2Sys()
REMOTE_SERIAL_DRIVER* SerCx2Sys_s()
{
/* _SerCxSys completed with default SerialSys functions */
PREMOTE_SERIAL_DRIVER serialSys = SerialSys();
/* _SerCx2Sys completed with SerialSys or SerCxSys default functions */
//REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s();
REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s();
_SerCx2Sys.set_baud_rate = serialSys->set_baud_rate;
_SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate;
_SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate;
_SerCx2Sys.get_properties = pSerCxSys->get_properties;
return &_SerCx2Sys;
}
#endif /* _WIN32 */

View File

@ -28,7 +28,7 @@
extern "C" {
#endif
WINPR_API PREMOTE_SERIAL_DRIVER SerCx2Sys();
REMOTE_SERIAL_DRIVER* SerCx2Sys_s();
#ifdef __cplusplus
}

View File

@ -20,25 +20,250 @@
* limitations under the License.
*/
#ifndef _WIN32
#include <assert.h>
#include <termios.h>
#include <freerdp/utils/debug.h>
#include "comm_serial_sys.h"
/* 0: B* (Linux termios)
* 1: CBR_* or actual baud rate
* 2: BAUD_* (similar to SERIAL_BAUD_*)
*/
static const speed_t _SERCX_SYS_BAUD_TABLE[][3] = {
#ifdef B0
{B0, 0, 0}, /* hang up */
#endif
#ifdef B50
{B50, 50, 0},
#endif
#ifdef B75
{B75, 75, BAUD_075},
#endif
#ifdef B110
{B110, CBR_110, BAUD_110},
#endif
#ifdef B134
{B134, 134, 0 /*BAUD_134_5*/},
#endif
#ifdef B150
{B150, 150, BAUD_150},
#endif
#ifdef B200
{B200, 200, 0},
#endif
#ifdef B300
{B300, CBR_300, BAUD_300},
#endif
#ifdef B600
{B600, CBR_600, BAUD_600},
#endif
#ifdef B1200
{B1200, CBR_1200, BAUD_1200},
#endif
#ifdef B1800
{B1800, 1800, BAUD_1800},
#endif
#ifdef B2400
{B2400, CBR_2400, BAUD_2400},
#endif
#ifdef B4800
{B4800, CBR_4800, BAUD_4800},
#endif
/* {, ,BAUD_7200} */
#ifdef B9600
{B9600, CBR_9600, BAUD_9600},
#endif
/* {, CBR_14400, BAUD_14400}, /\* unsupported on Linux *\/ */
#ifdef B19200
{B19200, CBR_19200, BAUD_19200},
#endif
#ifdef B38400
{B38400, CBR_38400, BAUD_38400},
#endif
/* {, CBR_56000, BAUD_56K}, /\* unsupported on Linux *\/ */
#ifdef B57600
{B57600, CBR_57600, BAUD_57600},
#endif
#ifdef B115200
{B115200, CBR_115200, BAUD_115200},
#endif
/* {, CBR_128000, BAUD_128K}, /\* unsupported on Linux *\/ */
/* {, CBR_256000, BAUD_USER}, /\* unsupported on Linux *\/ */
#ifdef B230400
{B230400, 230400, BAUD_USER},
#endif
#ifdef B460800
{B460800, 460800, BAUD_USER},
#endif
#ifdef B500000
{B500000, 500000, BAUD_USER},
#endif
#ifdef B576000
{B576000, 576000, BAUD_USER},
#endif
#ifdef B921600
{B921600, 921600, BAUD_USER},
#endif
#ifdef B1000000
{B1000000, 1000000, BAUD_USER},
#endif
#ifdef B1152000
{B1152000, 1152000, BAUD_USER},
#endif
#ifdef B1500000
{B1500000, 1500000, BAUD_USER},
#endif
#ifdef B2000000
{B2000000, 2000000, BAUD_USER},
#endif
#ifdef B2500000
{B2500000, 2500000, BAUD_USER},
#endif
#ifdef B3000000
{B3000000, 3000000, BAUD_USER},
#endif
#ifdef B3500000
{B3500000, 3500000, BAUD_USER},
#endif
#ifdef B4000000
{B4000000, 4000000, BAUD_USER}, /* __MAX_BAUD */
#endif
};
static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties)
{
int i;
// TMP: TODO:
// TMP: required?
// ZeroMemory(pProperties, sizeof(COMMPROP);
/* pProperties->PacketLength; */
/* pProperties->PacketVersion; */
/* pProperties->ServiceMask; */
/* pProperties->Reserved1; */
/* pProperties->MaxTxQueue; */
/* pProperties->MaxRxQueue; */
pProperties->dwMaxBaud = BAUD_USER;
/* pProperties->ProvSubType; */
/* pProperties->ProvCapabilities; */
/* pProperties->SettableParams; */
pProperties->dwSettableBaud = 0;
for (i=0; _SERCX_SYS_BAUD_TABLE[i][1]<=__MAX_BAUD; i++)
{
pProperties->dwSettableBaud |= _SERCX_SYS_BAUD_TABLE[i][2];
}
/* pProperties->SettableData; */
/* pProperties->SettableStopParity; */
/* pProperties->CurrentTxQueue; */
/* pProperties->CurrentRxQueue; */
/* pProperties->ProvSpec1; */
/* pProperties->ProvSpec2; */
/* pProperties->ProvChar[1]; */
return TRUE;
}
static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
{
int i;
speed_t newSpeed;
struct termios futureState;
ZeroMemory(&futureState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++)
{
if (_SERCX_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate)
{
newSpeed = _SERCX_SYS_BAUD_TABLE[i][0];
if (cfsetspeed(&futureState, newSpeed) < 0)
{
DEBUG_WARN("failed to set speed 0x%x (%d)", newSpeed, pBaudRate->BaudRate);
return FALSE;
}
assert(cfgetispeed(&futureState) == newSpeed);
if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0)
{
DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError());
return FALSE;
}
return TRUE;
}
}
DEBUG_WARN("could not find a matching speed for the baud rate %d", pBaudRate->BaudRate);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
{
int i;
speed_t currentSpeed;
struct termios currentState;
ZeroMemory(&currentState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentState) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
currentSpeed = cfgetispeed(&currentState);
for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++)
{
if (_SERCX_SYS_BAUD_TABLE[i][0] == currentSpeed)
{
pBaudRate->BaudRate = _SERCX_SYS_BAUD_TABLE[i][1];
return TRUE;
}
}
DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
/* specific functions only */
static REMOTE_SERIAL_DRIVER _SerCxSys =
{
.id = RemoteSerialDriverSerCxSys,
.name = _T("SerCx.sys"),
.set_baud_rate = NULL,
.set_baud_rate = _set_baud_rate,
.get_baud_rate = _get_baud_rate,
.get_properties = _get_properties,
};
PREMOTE_SERIAL_DRIVER SerCxSys()
REMOTE_SERIAL_DRIVER* SerCxSys_s()
{
/* _SerCxSys completed with default SerialSys functions */
PREMOTE_SERIAL_DRIVER serialSys = SerialSys();
_SerCxSys.set_baud_rate = serialSys->set_baud_rate;
//REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys();
return &_SerCxSys;
}
#endif /* _WIN32 */

View File

@ -28,7 +28,7 @@
extern "C" {
#endif
WINPR_API PREMOTE_SERIAL_DRIVER SerCxSys();
REMOTE_SERIAL_DRIVER* SerCxSys_s();
#ifdef __cplusplus
}

View File

@ -20,11 +20,227 @@
* limitations under the License.
*/
#ifndef _WIN32
#include <termios.h>
#include <freerdp/utils/debug.h>
#include "comm_serial_sys.h"
static BOOL _set_baud_rate(PSERIAL_BAUD_RATE pBaudRate)
{
#include <winpr/crt.h>
/*
* Linux, Windows speeds
*
*/
static const speed_t _SERIAL_SYS_BAUD_TABLE[][2] = {
#ifdef B0
{B0, 0}, /* hang up */
#endif
/* #ifdef B50 */
/* {B50, }, /\* undefined by serial.sys *\/ */
/* #endif */
#ifdef B75
{B75, SERIAL_BAUD_075},
#endif
#ifdef B110
{B110, SERIAL_BAUD_110},
#endif
/* #ifdef B134 */
/* {B134, SERIAL_BAUD_134_5}, /\* TODO: might be the same? *\/ */
/* #endif */
#ifdef B150
{B150, SERIAL_BAUD_150},
#endif
/* #ifdef B200 */
/* {B200, }, /\* undefined by serial.sys *\/ */
/* #endif */
#ifdef B300
{B300, SERIAL_BAUD_300},
#endif
#ifdef B600
{B600, SERIAL_BAUD_600},
#endif
#ifdef B1200
{B1200, SERIAL_BAUD_1200},
#endif
#ifdef B1800
{B1800, SERIAL_BAUD_1800},
#endif
#ifdef B2400
{B2400, SERIAL_BAUD_2400},
#endif
#ifdef B4800
{B4800, SERIAL_BAUD_4800},
#endif
/* {, SERIAL_BAUD_7200} /\* undefined on Linux *\/ */
#ifdef B9600
{B9600, SERIAL_BAUD_9600},
#endif
/* {, SERIAL_BAUD_14400} /\* undefined on Linux *\/ */
#ifdef B19200
{B19200, SERIAL_BAUD_19200},
#endif
#ifdef B38400
{B38400, SERIAL_BAUD_38400},
#endif
/* {, SERIAL_BAUD_56K}, /\* undefined on Linux *\/ */
#ifdef B57600
{B57600, SERIAL_BAUD_57600},
#endif
/* {, SERIAL_BAUD_128K} /\* undefined on Linux *\/ */
#ifdef B115200
{B115200, SERIAL_BAUD_115200}, /* _SERIAL_MAX_BAUD */
#endif
/* undefined by serial.sys:
#ifdef B230400
{B230400, },
#endif
#ifdef B460800
{B460800, },
#endif
#ifdef B500000
{B500000, },
#endif
#ifdef B576000
{B576000, },
#endif
#ifdef B921600
{B921600, },
#endif
#ifdef B1000000
{B1000000, },
#endif
#ifdef B1152000
{B1152000, },
#endif
#ifdef B1500000
{B1500000, },
#endif
#ifdef B2000000
{B2000000, },
#endif
#ifdef B2500000
{B2500000, },
#endif
#ifdef B3000000
{B3000000, },
#endif
#ifdef B3500000
{B3500000, },
#endif
#ifdef B4000000
{B4000000, }, __MAX_BAUD
#endif
*/
};
#define _SERIAL_MAX_BAUD B115200
static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties)
{
int i;
// TMP: TODO:
// TMP: required?
// ZeroMemory(pProperties, sizeof(COMMPROP);
/* pProperties->PacketLength; */
/* pProperties->PacketVersion; */
/* pProperties->ServiceMask; */
/* pProperties->Reserved1; */
/* pProperties->MaxTxQueue; */
/* pProperties->MaxRxQueue; */
pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */
/* pProperties->ProvSubType; */
/* pProperties->ProvCapabilities; */
/* pProperties->SettableParams; */
pProperties->dwSettableBaud = 0;
for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++)
{
pProperties->dwSettableBaud |= _SERIAL_SYS_BAUD_TABLE[i][1];
}
/* pProperties->SettableData; */
/* pProperties->SettableStopParity; */
/* pProperties->CurrentTxQueue; */
/* pProperties->CurrentRxQueue; */
/* pProperties->ProvSpec1; */
/* pProperties->ProvSpec2; */
/* pProperties->ProvChar[1]; */
return TRUE;
}
static BOOL _set_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
{
int i;
speed_t newSpeed;
struct termios futureState;
ZeroMemory(&futureState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++)
{
if (_SERIAL_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate)
{
newSpeed = _SERIAL_SYS_BAUD_TABLE[i][0];
if (cfsetspeed(&futureState, newSpeed) < 0)
{
DEBUG_WARN("failed to set speed %d (%d)", newSpeed, pBaudRate->BaudRate);
return FALSE;
}
if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0)
{
DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError());
return FALSE;
}
return TRUE;
}
}
DEBUG_WARN("could not find a matching speed for the baud rate %d", pBaudRate->BaudRate);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
{
int i;
speed_t currentSpeed;
struct termios currentState;
ZeroMemory(&currentState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentState) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
currentSpeed = cfgetispeed(&currentState);
for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++)
{
if (_SERIAL_SYS_BAUD_TABLE[i][0] == currentSpeed)
{
pBaudRate->BaudRate = _SERIAL_SYS_BAUD_TABLE[i][1];
return TRUE;
}
}
DEBUG_WARN("could not find a matching baud rate for the speed 0x%x", currentSpeed);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
@ -34,10 +250,14 @@ static REMOTE_SERIAL_DRIVER _SerialSys =
.id = RemoteSerialDriverSerialSys,
.name = _T("Serial.sys"),
.set_baud_rate = _set_baud_rate,
.get_baud_rate = _get_baud_rate,
.get_properties = _get_properties,
};
PREMOTE_SERIAL_DRIVER SerialSys()
REMOTE_SERIAL_DRIVER* SerialSys_s()
{
return &_SerialSys;
}
#endif /* _WIN32 */

View File

@ -28,7 +28,30 @@
extern "C" {
#endif
WINPR_API PREMOTE_SERIAL_DRIVER SerialSys();
/* Ntddser.h: http://msdn.microsoft.com/en-us/cc308432.aspx */
#define SERIAL_BAUD_075 ((ULONG)0x00000001)
#define SERIAL_BAUD_110 ((ULONG)0x00000002)
#define SERIAL_BAUD_134_5 ((ULONG)0x00000004)
#define SERIAL_BAUD_150 ((ULONG)0x00000008)
#define SERIAL_BAUD_300 ((ULONG)0x00000010)
#define SERIAL_BAUD_600 ((ULONG)0x00000020)
#define SERIAL_BAUD_1200 ((ULONG)0x00000040)
#define SERIAL_BAUD_1800 ((ULONG)0x00000080)
#define SERIAL_BAUD_2400 ((ULONG)0x00000100)
#define SERIAL_BAUD_4800 ((ULONG)0x00000200)
#define SERIAL_BAUD_7200 ((ULONG)0x00000400)
#define SERIAL_BAUD_9600 ((ULONG)0x00000800)
#define SERIAL_BAUD_14400 ((ULONG)0x00001000)
#define SERIAL_BAUD_19200 ((ULONG)0x00002000)
#define SERIAL_BAUD_38400 ((ULONG)0x00004000)
#define SERIAL_BAUD_56K ((ULONG)0x00008000)
#define SERIAL_BAUD_128K ((ULONG)0x00010000)
#define SERIAL_BAUD_115200 ((ULONG)0x00020000)
#define SERIAL_BAUD_57600 ((ULONG)0x00040000)
#define SERIAL_BAUD_USER ((ULONG)0x10000000)
REMOTE_SERIAL_DRIVER* SerialSys_s();
#ifdef __cplusplus
}

View File

@ -28,7 +28,7 @@ int TestCommConfig(int argc, char* argv[])
{
DCB dcb;
HANDLE hComm;
BOOL fSuccess;
BOOL success;
LPCSTR lpFileName = "\\\\.\\COM1";
hComm = CreateFileA(lpFileName,
@ -41,8 +41,9 @@ int TestCommConfig(int argc, char* argv[])
return EXIT_FAILURE;
}
fSuccess = DefineCommDevice(lpFileName, "/dev/null");
if(!fSuccess)
// TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail
success = DefineCommDevice(lpFileName, "/dev/ttyS0");
if(!success)
{
printf("DefineCommDevice failure: %s\n", lpFileName);
return EXIT_FAILURE;
@ -68,7 +69,7 @@ int TestCommConfig(int argc, char* argv[])
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
printf("CreateFileA failure: %s\n", lpFileName);
printf("CreateFileA failure: %s GetLastError() = 0x%0.8x\n", lpFileName, GetLastError());
return EXIT_FAILURE;
}
@ -76,11 +77,11 @@ int TestCommConfig(int argc, char* argv[])
* GetLastError should return ERROR_SHARING_VIOLATION */
ZeroMemory(&dcb, sizeof(DCB));
fSuccess = GetCommState(hComm, &dcb);
if (!fSuccess)
dcb.DCBlength = sizeof(DCB);
success = GetCommState(hComm, &dcb);
if (!success)
{
printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError());
printf("GetCommState failure: GetLastError() = Ox%x\n", (int) GetLastError());
return EXIT_FAILURE;
}
@ -92,19 +93,19 @@ int TestCommConfig(int argc, char* argv[])
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
fSuccess = SetCommState(hComm, &dcb);
success = SetCommState(hComm, &dcb);
if (!fSuccess)
if (!success)
{
printf("SetCommState failure: GetLastError() = %d\n", (int) GetLastError());
printf("SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError());
return 0;
}
fSuccess = GetCommState(hComm, &dcb);
success = GetCommState(hComm, &dcb);
if (!fSuccess)
if (!success)
{
printf("GetCommState failure: GetLastError() = %d\n", (int) GetLastError());
printf("GetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError());
return 0;
}

View File

@ -119,7 +119,6 @@ int TestSetCommState(int argc, char* argv[])
HANDLE hComm;
// TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
@ -149,7 +148,7 @@ int TestSetCommState(int argc, char* argv[])
result = SetCommState(hComm, &dcb);
if (!result)
{
printf("SetCommState failure: 0x%x\n", GetLastError());
printf("SetCommState failure: 0x%0.8x\n", GetLastError());
return EXIT_FAILURE;
}