winpr-comm: fixed _set_lines() / _clear_lines()

winpr-comm: got IOCTL_SERIAL_SET_WAIT_MASK / IOCTL_SERIAL_GET_WAIT_MASK and a non-blocking version of IOCTL_SERIAL_WAIT_ON_MASK
This commit is contained in:
Emmanuel Ledoux 2014-05-14 16:29:10 +02:00 committed by Emmanuel Ledoux
parent 116995f865
commit 4243928c2e
9 changed files with 645 additions and 83 deletions

View File

@ -364,7 +364,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
Stream_Read(irp->input, InputBuffer, InputBufferLength); Stream_Read(irp->input, InputBuffer, InputBufferLength);
DEBUG_SVC("CommDeviceIoControl: IoControlCode 0x%x", IoControlCode); DEBUG_SVC("CommDeviceIoControl: IoControlCode=[0x%x] %s", IoControlCode, _comm_serial_ioctl_name(IoControlCode));
/* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */
if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL))
@ -373,7 +373,10 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
} }
else else
{ {
DEBUG_SVC("CommDeviceIoControl failure: IoControlCode 0x%0.8x last-error: 0x%x", IoControlCode, GetLastError()); DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%x",
IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError());
// TMP: TODO: Status code to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests
switch(GetLastError()) switch(GetLastError())
{ {
@ -397,9 +400,14 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
irp->IoStatus = STATUS_NOT_IMPLEMENTED; irp->IoStatus = STATUS_NOT_IMPLEMENTED;
break; break;
case ERROR_IO_PENDING:
irp->IoStatus = STATUS_PENDING;
break;
default: default:
DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); DEBUG_SVC("unexpected last-error: 0x%x", GetLastError());
irp->IoStatus = STATUS_UNSUCCESSFUL; //irp->IoStatus = STATUS_UNSUCCESSFUL;
irp->IoStatus = STATUS_CANCELLED;
break; break;
} }
} }

View File

@ -401,6 +401,129 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004
#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050
#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C
#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054
#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C
#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020
/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */
#define IOCTL_SERIAL_GET_CHARS 0x001B0058
#define IOCTL_SERIAL_SET_CHARS 0x001B005C
#define IOCTL_SERIAL_SET_DTR 0x001B0024
#define IOCTL_SERIAL_CLR_DTR 0x001B0028
/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */
#define IOCTL_SERIAL_SET_RTS 0x001B0030
#define IOCTL_SERIAL_CLR_RTS 0x001B0034
/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */
/* IOCTL_SERIAL_SET_XON 0x001B003C */
/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */
/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */
/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */
#define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040
#define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044
#define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048
/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */
/* IOCTL_SERIAL_PURGE 0x001B004C */
#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060
#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064
#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068
/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */
/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */
#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074
/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */
/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */
/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */
/* IOCTL_SERIAL_GET_STATS 0x001B008C */
/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */
/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */
/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */
/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */
/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */
/* IOCTL_PAR_SET_INFORMATION 0x00160008 */
/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */
/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */
/* IOCTL_IEEE1284_GET_MODE 0x00160014 */
/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */
/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */
/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */
/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */
/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */
/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */
/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */
typedef struct __SERIAL_IOCTL_NAME
{
ULONG number;
const char* name;
} _SERIAL_IOCTL_NAME;
static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] =
{
{IOCTL_SERIAL_SET_BAUD_RATE, "IOCTL_SERIAL_SET_BAUD_RATE"},
{IOCTL_SERIAL_GET_BAUD_RATE, "IOCTL_SERIAL_GET_BAUD_RATE"},
{IOCTL_SERIAL_SET_LINE_CONTROL, "IOCTL_SERIAL_SET_LINE_CONTROL"},
{IOCTL_SERIAL_GET_LINE_CONTROL, "IOCTL_SERIAL_GET_LINE_CONTROL"},
{IOCTL_SERIAL_SET_TIMEOUTS, "IOCTL_SERIAL_SET_TIMEOUTS"},
{IOCTL_SERIAL_GET_TIMEOUTS, "IOCTL_SERIAL_GET_TIMEOUTS"},
{IOCTL_SERIAL_GET_CHARS, "IOCTL_SERIAL_GET_CHARS"},
{IOCTL_SERIAL_SET_CHARS, "IOCTL_SERIAL_SET_CHARS"},
{IOCTL_SERIAL_SET_DTR, "IOCTL_SERIAL_SET_DTR"},
{IOCTL_SERIAL_CLR_DTR, "IOCTL_SERIAL_CLR_DTR"},
// {IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"},
{IOCTL_SERIAL_SET_RTS, "IOCTL_SERIAL_SET_RTS"},
{IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"},
// {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"},
// {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"},
// {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"},
// {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"},
// {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"},
{IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"},
{IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"},
{IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"},
// {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"},
// {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"},
{IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"},
{IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"},
{IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"},
// {IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"},
// {IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"},
{IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"},
// {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"},
// {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"},
// {IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"},
// {IOCTL_SERIAL_GET_STATS, "IOCTL_SERIAL_GET_STATS"},
// {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"};
// {IOCTL_SERIAL_GET_MODEM_CONTROL,"IOCTL_SERIAL_GET_MODEM_CONTROL"},
// {IOCTL_SERIAL_SET_MODEM_CONTROL,"IOCTL_SERIAL_SET_MODEM_CONTROL"},
// {IOCTL_SERIAL_SET_FIFO_CONTROL, "IOCTL_SERIAL_SET_FIFO_CONTROL"},
// {IOCTL_PAR_QUERY_INFORMATION, "IOCTL_PAR_QUERY_INFORMATION"},
// {IOCTL_PAR_SET_INFORMATION, "IOCTL_PAR_SET_INFORMATION"},
// {IOCTL_PAR_QUERY_DEVICE_ID, "IOCTL_PAR_QUERY_DEVICE_ID"},
// {IOCTL_PAR_QUERY_DEVICE_ID_SIZE,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE"},
// {IOCTL_IEEE1284_GET_MODE, "IOCTL_IEEE1284_GET_MODE"},
// {IOCTL_IEEE1284_NEGOTIATE, "IOCTL_IEEE1284_NEGOTIATE"},
// {IOCTL_PAR_SET_WRITE_ADDRESS, "IOCTL_PAR_SET_WRITE_ADDRESS"},
// {IOCTL_PAR_SET_READ_ADDRESS, "IOCTL_PAR_SET_READ_ADDRESS"},
// {IOCTL_PAR_GET_DEVICE_CAPS, "IOCTL_PAR_GET_DEVICE_CAPS"},
// {IOCTL_PAR_GET_DEFAULT_MODES, "IOCTL_PAR_GET_DEFAULT_MODES"},
// {IOCTL_PAR_QUERY_RAW_DEVICE_ID, "IOCTL_PAR_QUERY_RAW_DEVICE_ID"},
// {IOCTL_PAR_IS_PORT_FREE, "IOCTL_PAR_IS_PORT_FREE"},
{0, NULL}
};
/**
* FIXME: got a proper function name and place
*/
const char* _comm_serial_ioctl_name(ULONG number);
/** /**
* FIXME: to be moved in comm_ioctl.h * FIXME: to be moved in comm_ioctl.h
*/ */

View File

@ -27,6 +27,7 @@
#ifndef _WIN32 #ifndef _WIN32
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <termios.h> #include <termios.h>
@ -1099,6 +1100,17 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare
*/ */
pComm->remoteSerialDriverId = RemoteSerialDriverUnknown; pComm->remoteSerialDriverId = RemoteSerialDriverUnknown;
if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0)
{
DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
goto error_handle;
}
/* The binary/raw mode is required for the redirection but /* The binary/raw mode is required for the redirection but
* only flags that are not handle somewhere-else, except * only flags that are not handle somewhere-else, except

View File

@ -23,6 +23,8 @@
#ifndef _WIN32 #ifndef _WIN32
#include <linux/serial.h>
#include <winpr/comm.h> #include <winpr/comm.h>
#include "../handle/handle.h" #include "../handle/handle.h"
@ -47,6 +49,10 @@ struct winpr_comm
REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId; REMOTE_SERIAL_DRIVER_ID remoteSerialDriverId;
COMMTIMEOUTS timeouts; COMMTIMEOUTS timeouts;
struct serial_icounter_struct counters;
ULONG waitMask;
ULONG pendingEvents;
/* NB: CloseHandle() has to free resources */ /* NB: CloseHandle() has to free resources */
}; };

View File

@ -56,9 +56,27 @@
*/ */
const char* _comm_serial_ioctl_name(ULONG number)
{
int i;
for (i=0; _SERIAL_IOCTL_NAMES[i].number != 0; i++)
{
if (_SERIAL_IOCTL_NAMES[i].number == number)
{
return _SERIAL_IOCTL_NAMES[i].name;
}
}
return "(unknown ioctl name)";
}
/** /**
* FIXME: to be used through winpr-io's DeviceIoControl * FIXME: to be used through winpr-io's DeviceIoControl
* *
* Any previous error as returned by GetLastError is cleared.
*
* ERRORS: * ERRORS:
* ERROR_INVALID_HANDLE * ERROR_INVALID_HANDLE
* ERROR_INVALID_PARAMETER * ERROR_INVALID_PARAMETER
@ -73,6 +91,9 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
WINPR_COMM* pComm = (WINPR_COMM*) hDevice; WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL; REMOTE_SERIAL_DRIVER* pRemoteSerialDriver = NULL;
/* clear any previous last error */
SetLastError(ERROR_SUCCESS);
if (hDevice == INVALID_HANDLE_VALUE) if (hDevice == INVALID_HANDLE_VALUE)
{ {
SetLastError(ERROR_INVALID_HANDLE); SetLastError(ERROR_INVALID_HANDLE);
@ -394,9 +415,69 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
} }
break; break;
} }
case IOCTL_SERIAL_SET_WAIT_MASK:
{
if (pRemoteSerialDriver->set_wait_mask)
{
ULONG *pWaitMask = (ULONG*)lpInBuffer;
assert(nInBufferSize >= sizeof(ULONG));
if (nInBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pRemoteSerialDriver->set_wait_mask(pComm, pWaitMask);
}
break;
}
case IOCTL_SERIAL_GET_WAIT_MASK:
{
if (pRemoteSerialDriver->get_wait_mask)
{
ULONG *pWaitMask = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pRemoteSerialDriver->get_wait_mask(pComm, pWaitMask))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_WAIT_ON_MASK:
{
if (pRemoteSerialDriver->wait_on_mask)
{
ULONG *pOutputMask = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pRemoteSerialDriver->wait_on_mask(pComm, pOutputMask))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
} }
DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name); DEBUG_WARN(_T("unsupported IoControlCode=[Ox%0.8x] %s (remote serial driver: %s)"),
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pRemoteSerialDriver->name);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;

View File

@ -42,59 +42,6 @@ extern "C" {
#endif #endif
#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004
#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050
#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C
#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054
#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C
#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020
/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */
#define IOCTL_SERIAL_GET_CHARS 0x001B0058
#define IOCTL_SERIAL_SET_CHARS 0x001B005C
#define IOCTL_SERIAL_SET_DTR 0x001B0024
#define IOCTL_SERIAL_CLR_DTR 0x001B0028
/* IOCTL_SERIAL_RESET_DEVICE 0x001B002C */
#define IOCTL_SERIAL_SET_RTS 0x001B0030
#define IOCTL_SERIAL_CLR_RTS 0x001B0034
/* IOCTL_SERIAL_SET_XOFF 0x001B0038 */
/* IOCTL_SERIAL_SET_XON 0x001B003C */
/* IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 */
/* IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 */
/* IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 */
/* IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 */
/* IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 */
/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */
/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */
/* IOCTL_SERIAL_PURGE 0x001B004C */
#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060
#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064
#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068
/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */
/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */
#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074
/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */
/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */
/* IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 */
/* IOCTL_SERIAL_GET_STATS 0x001B008C */
/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */
/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */
/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */
/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */
/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */
/* IOCTL_PAR_SET_INFORMATION 0x00160008 */
/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */
/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */
/* IOCTL_IEEE1284_GET_MODE 0x00160014 */
/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */
/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */
/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */
/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */
/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */
/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */
/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */
#define STOP_BIT_1 0 #define STOP_BIT_1 0
#define STOP_BITS_1_5 1 #define STOP_BITS_1_5 1
@ -200,6 +147,20 @@ typedef struct _SERIAL_TIMEOUTS
#define SERIAL_MSR_DCD 0x80 #define SERIAL_MSR_DCD 0x80
#define SERIAL_EV_RXCHAR 0x0001
#define SERIAL_EV_RXFLAG 0x0002
#define SERIAL_EV_TXEMPTY 0x0004
#define SERIAL_EV_CTS 0x0008
#define SERIAL_EV_DSR 0x0010
#define SERIAL_EV_RLSD 0x0020
#define SERIAL_EV_BREAK 0x0040
#define SERIAL_EV_ERR 0x0080
#define SERIAL_EV_RING 0x0100
#define SERIAL_EV_PERR 0x0200
#define SERIAL_EV_RX80FULL 0x0400
#define SERIAL_EV_EVENT1 0x0800
#define SERIAL_EV_EVENT2 0x1000
/** /**
* A function might be NULL if not supported by the underlying remote driver. * A function might be NULL if not supported by the underlying remote driver.
* *
@ -225,6 +186,9 @@ typedef struct _REMOTE_SERIAL_DRIVER
BOOL (*set_rts)(WINPR_COMM *pComm); BOOL (*set_rts)(WINPR_COMM *pComm);
BOOL (*clear_rts)(WINPR_COMM *pComm); BOOL (*clear_rts)(WINPR_COMM *pComm);
BOOL (*get_modemstatus)(WINPR_COMM *pComm, ULONG *pRegister); BOOL (*get_modemstatus)(WINPR_COMM *pComm, ULONG *pRegister);
BOOL (*set_wait_mask)(WINPR_COMM *pComm, const ULONG *pWaitMask);
BOOL (*get_wait_mask)(WINPR_COMM *pComm, ULONG *pWaitMask);
BOOL (*wait_on_mask)(WINPR_COMM *pComm, ULONG *pOutputMask);
} REMOTE_SERIAL_DRIVER; } REMOTE_SERIAL_DRIVER;

View File

@ -22,6 +22,8 @@
#ifndef _WIN32 #ifndef _WIN32
#include <freerdp/utils/debug.h>
#include "comm_serial_sys.h" #include "comm_serial_sys.h"
#include "comm_sercx_sys.h" #include "comm_sercx_sys.h"
@ -52,6 +54,45 @@ static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
} }
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
/* FIXME: only using the Serial.sys' events, complete the support of the remaining events */
static const ULONG _SERCX2_SYS_SUPPORTED_EV_MASK =
SERIAL_EV_RXCHAR |
SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING |
/* SERIAL_EV_PERR | */
SERIAL_EV_RX80FULL /*|
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/;
/* use Serial.sys for basis (not SerCx.sys) */
static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask)
{
ULONG possibleMask;
REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s();
possibleMask = *pWaitMask & _SERCX2_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
DEBUG_WARN("Not all wait events supported (SerCx2.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->waitMask = possibleMask;
return FALSE;
}
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
return pSerialSys->set_wait_mask(pComm, pWaitMask);
}
/* specific functions only */ /* specific functions only */
static REMOTE_SERIAL_DRIVER _SerCx2Sys = static REMOTE_SERIAL_DRIVER _SerCx2Sys =
{ {
@ -73,6 +114,9 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys =
.set_rts = NULL, .set_rts = NULL,
.clear_rts = NULL, .clear_rts = NULL,
.get_modemstatus = NULL, .get_modemstatus = NULL,
.set_wait_mask = _set_wait_mask,
.get_wait_mask = NULL,
.wait_on_mask = NULL,
}; };
@ -107,6 +151,10 @@ REMOTE_SERIAL_DRIVER* SerCx2Sys_s()
_SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus; _SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus;
_SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask;
_SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask;
_SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask;
return &_SerCx2Sys; return &_SerCx2Sys;
} }

View File

@ -492,6 +492,43 @@ static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow)
} }
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK =
SERIAL_EV_RXCHAR |
/* SERIAL_EV_RXFLAG | */
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING /* |
SERIAL_EV_PERR |
SERIAL_EV_RX80FULL |
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/;
static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask)
{
ULONG possibleMask;
REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s();
possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
DEBUG_WARN("Not all wait events supported (SerCx.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->waitMask = possibleMask;
return FALSE;
}
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
return pSerialSys->set_wait_mask(pComm, pWaitMask);
}
/* specific functions only */ /* specific functions only */
static REMOTE_SERIAL_DRIVER _SerCxSys = static REMOTE_SERIAL_DRIVER _SerCxSys =
@ -514,6 +551,9 @@ static REMOTE_SERIAL_DRIVER _SerCxSys =
.set_rts = NULL, .set_rts = NULL,
.clear_rts = NULL, .clear_rts = NULL,
.get_modemstatus = NULL, .get_modemstatus = NULL,
.set_wait_mask = _set_wait_mask,
.get_wait_mask = NULL,
.wait_on_mask = NULL,
}; };
@ -539,6 +579,10 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s()
_SerCxSys.get_modemstatus = pSerialSys->get_modemstatus; _SerCxSys.get_modemstatus = pSerialSys->get_modemstatus;
_SerCxSys.set_wait_mask = pSerialSys->set_wait_mask;
_SerCxSys.get_wait_mask = pSerialSys->get_wait_mask;
_SerCxSys.wait_on_mask = pSerialSys->wait_on_mask;
return &_SerCxSys; return &_SerCxSys;
} }

View File

@ -23,6 +23,7 @@
#ifndef _WIN32 #ifndef _WIN32
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <termios.h> #include <termios.h>
@ -140,6 +141,7 @@ static const speed_t _SERIAL_SYS_BAUD_TABLE[][2] = {
#define _SERIAL_MAX_BAUD B115200 #define _SERIAL_MAX_BAUD B115200
static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties)
{ {
int i; int i;
@ -559,6 +561,7 @@ static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineContr
/* hard-coded in N_TTY */ /* hard-coded in N_TTY */
#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
#define TTY_THRESHOLD_UNTHROTTLE 128 #define TTY_THRESHOLD_UNTHROTTLE 128
#define N_TTY_BUF_SIZE 4096
static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow)
{ {
@ -862,16 +865,28 @@ static BOOL _get_timeouts(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts)
} }
static BOOL _set_line(WINPR_COMM *pComm, UINT32 line) static BOOL _set_lines(WINPR_COMM *pComm, UINT32 lines)
{ {
ioctl(pComm->fd, TIOCMBIS, line); if (ioctl(pComm->fd, TIOCMBIS, &lines) < 0)
{
DEBUG_WARN("TIOCMBIS ioctl failed, lines=0x%0.4X, errno=[%d] %s", lines, errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
return TRUE; return TRUE;
} }
static BOOL _clear_line(WINPR_COMM *pComm, UINT32 line) static BOOL _clear_lines(WINPR_COMM *pComm, UINT32 lines)
{ {
ioctl(pComm->fd, TIOCMBIC, line); if (ioctl(pComm->fd, TIOCMBIC, &lines) < 0)
{
DEBUG_WARN("TIOCMBIC ioctl failed, lines=0x%0.4X, errno=[%d] %s", lines, errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
return TRUE; return TRUE;
} }
@ -891,7 +906,7 @@ static BOOL _set_dtr(WINPR_COMM *pComm)
return FALSE; return FALSE;
} }
return _set_line(pComm, TIOCM_DTR); return _set_lines(pComm, TIOCM_DTR);
} }
static BOOL _clear_dtr(WINPR_COMM *pComm) static BOOL _clear_dtr(WINPR_COMM *pComm)
@ -909,37 +924,39 @@ static BOOL _clear_dtr(WINPR_COMM *pComm)
return FALSE; return FALSE;
} }
return _clear_line(pComm, TIOCM_DTR); return _clear_lines(pComm, TIOCM_DTR);
} }
static BOOL _set_rts(WINPR_COMM *pComm) static BOOL _set_rts(WINPR_COMM *pComm)
{ {
SERIAL_HANDFLOW handflow; // TMP: really required?
if (!_get_handflow(pComm, &handflow)) /* SERIAL_HANDFLOW handflow; */
return FALSE; /* if (!_get_handflow(pComm, &handflow)) */
/* return FALSE; */
if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) /* if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) */
{ /* { */
SetLastError(ERROR_INVALID_PARAMETER); /* SetLastError(ERROR_INVALID_PARAMETER); */
return FALSE; /* return FALSE; */
} /* } */
return _set_line(pComm, TIOCM_RTS); return _set_lines(pComm, TIOCM_RTS);
} }
static BOOL _clear_rts(WINPR_COMM *pComm) static BOOL _clear_rts(WINPR_COMM *pComm)
{ {
SERIAL_HANDFLOW handflow; // TMP: really required?
if (!_get_handflow(pComm, &handflow)) /* SERIAL_HANDFLOW handflow; */
return FALSE; /* if (!_get_handflow(pComm, &handflow)) */
/* return FALSE; */
if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) /* if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) */
{ /* { */
SetLastError(ERROR_INVALID_PARAMETER); /* SetLastError(ERROR_INVALID_PARAMETER); */
return FALSE; /* return FALSE; */
} /* } */
return _clear_line(pComm, TIOCM_RTS); return _clear_lines(pComm, TIOCM_RTS);
} }
@ -947,7 +964,12 @@ static BOOL _clear_rts(WINPR_COMM *pComm)
static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister)
{ {
UINT32 lines=0; UINT32 lines=0;
ioctl(pComm->fd, TIOCMGET, &lines); if (ioctl(pComm->fd, TIOCMGET, &lines) < 0)
{
DEBUG_WARN("TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
ZeroMemory(pRegister, sizeof(ULONG)); ZeroMemory(pRegister, sizeof(ULONG));
@ -972,6 +994,257 @@ static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister)
return TRUE; return TRUE;
} }
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK =
SERIAL_EV_RXCHAR |
SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING |
/* SERIAL_EV_PERR | */
SERIAL_EV_RX80FULL /*|
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/;
static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask)
{
ULONG possibleMask;
if (*pWaitMask == 0)
{
/* clearing pending events */
// TMP: TODO:
if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0)
{
DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
pComm->pendingEvents = 0;
}
// TMP: TODO:
// pending wait_on_mask must be stopped with STATUS_SUCCESS
// http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx
possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
DEBUG_WARN("Not all wait events supported (Serial.sys), requested events= 0X%0.4X, possible events= 0X%0.4X", *pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->waitMask = possibleMask;
return FALSE;
}
pComm->waitMask = possibleMask;
return TRUE;
}
static BOOL _get_wait_mask(WINPR_COMM *pComm, ULONG *pWaitMask)
{
*pWaitMask = pComm->waitMask;
return TRUE;
}
static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask)
{
assert(*pOutputMask == 0);
/* TMP: TODO: while (TRUE) */
{
int nbBytesToBeRead = 0;
int nbBytesToBeWritten = 0;
struct serial_icounter_struct currentCounters;
ULONG tiocmiwaitMask = 0; /* TIOCMIWAIT can wait for the 4 lines: TIOCM_RNG/DSR/CD/CTS */
if (ioctl(pComm->fd, TIOCINQ, &nbBytesToBeRead) < 0)
{
DEBUG_WARN("TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
if (ioctl(pComm->fd, TIOCOUTQ, &nbBytesToBeWritten) < 0)
{
DEBUG_WARN("TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
ZeroMemory(&currentCounters, sizeof(struct serial_icounter_struct));
if (ioctl(pComm->fd, TIOCGICOUNT, &currentCounters) < 0)
{
DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
/* NB: preferred below "currentCounters.* != pComm->counters.*" over "currentCounters.* > pComm->counters.*" thinking the counters can loop */
/* events */
if (pComm->waitMask & SERIAL_EV_RXCHAR)
{
if (nbBytesToBeRead > 0)
{
/* at least one character is pending to be read */
*pOutputMask |= SERIAL_EV_RXCHAR;
}
}
if (pComm->waitMask & SERIAL_EV_RXFLAG)
{
if (pComm->pendingEvents & SERIAL_EV_RXFLAG) // TMP: to be done in the ReadThread
{
/* the event character was received FIXME: is the character supposed to be still in the input buffer? */
/* event consumption */
pComm->pendingEvents &= ~SERIAL_EV_RXFLAG;
*pOutputMask |= SERIAL_EV_RXFLAG;
}
}
if (pComm->waitMask & SERIAL_EV_TXEMPTY)
{
if (nbBytesToBeWritten == 0)
{
/* NB: as of today CommWriteFile still blocks and uses the same thread than CommDeviceIoControl,
* it should be enough to just check nbBytesToBeWritten
*/
/* the output buffer is empty */
*pOutputMask |= SERIAL_EV_TXEMPTY;
}
}
if (pComm->waitMask & SERIAL_EV_CTS)
{
tiocmiwaitMask |= TIOCM_CTS;
}
if (pComm->waitMask & SERIAL_EV_DSR)
{
tiocmiwaitMask |= TIOCM_DSR;
}
if (pComm->waitMask & SERIAL_EV_RLSD)
{
tiocmiwaitMask |= TIOCM_CD;
}
if (pComm->waitMask & SERIAL_EV_BREAK)
{
if (currentCounters.brk != pComm->counters.brk)
{
*pOutputMask |= SERIAL_EV_BREAK;
/* event consumption */
pComm->counters.brk = currentCounters.brk;
}
}
if (pComm->waitMask & SERIAL_EV_ERR)
{
if ((currentCounters.frame != pComm->counters.frame) ||
(currentCounters.overrun != pComm->counters.overrun) ||
(currentCounters.parity != pComm->counters.parity))
{
*pOutputMask |= SERIAL_EV_ERR;
/* event consumption */
pComm->counters.frame = currentCounters.frame;
pComm->counters.overrun = currentCounters.overrun;
pComm->counters.parity = currentCounters.parity;
}
}
if (pComm->waitMask & SERIAL_EV_RING)
{
tiocmiwaitMask |= TIOCM_RNG;
}
if (pComm->waitMask & SERIAL_EV_RX80FULL)
{
if (nbBytesToBeRead > (0.8 * N_TTY_BUF_SIZE))
*pOutputMask |= SERIAL_EV_RX80FULL;
}
if ((*pOutputMask == 0) && /* don't need to wait more if at least an event already occured */
(tiocmiwaitMask > 0))
{
if ((pComm->waitMask & SERIAL_EV_CTS) && currentCounters.cts != pComm->counters.cts)
{
*pOutputMask |= SERIAL_EV_CTS;
/* event consumption */
pComm->counters.cts = currentCounters.cts;
}
if ((pComm->waitMask & SERIAL_EV_DSR) && currentCounters.dsr != pComm->counters.dsr)
{
*pOutputMask |= SERIAL_EV_DSR;
/* event consumption */
pComm->counters.dsr = currentCounters.dsr;
}
if ((pComm->waitMask & SERIAL_EV_RLSD) && currentCounters.dcd != pComm->counters.dcd)
{
*pOutputMask |= SERIAL_EV_RLSD;
/* event consumption */
pComm->counters.dcd = currentCounters.dcd;
}
if ((pComm->waitMask & SERIAL_EV_RING) && currentCounters.rng != pComm->counters.rng)
{
*pOutputMask |= SERIAL_EV_RING;
/* event consumption */
pComm->counters.rng = currentCounters.rng;
}
/* FIXME: TIOCMIWAIT could be possible if _wait_on_mask gets its own thread */
/* if (*pOutputMask == 0) */
/* { */
/* if (ioctl(pComm->fd, TIOCMIWAIT, &tiocmiwaitMask) < 0) */
/* { */
/* DEBUG_WARN("TIOCMIWAIT ioctl failed, errno=[%d] %s", errno, strerror(errno)); */
/* SetLastError(ERROR_IO_DEVICE); */
/* return FALSE; */
/* } */
/* /\* TODO: check counters again after TIOCMIWAIT *\/ */
/* } */
}
if (*pOutputMask != 0)
{
/* at least an event occurred */
return TRUE;
}
}
DEBUG_WARN("_wait_on_mask pending on events:0X%0.4X", pComm->waitMask);
SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */
return FALSE;
}
static REMOTE_SERIAL_DRIVER _SerialSys = static REMOTE_SERIAL_DRIVER _SerialSys =
{ {
@ -993,6 +1266,9 @@ static REMOTE_SERIAL_DRIVER _SerialSys =
.set_rts = _set_rts, .set_rts = _set_rts,
.clear_rts = _clear_rts, .clear_rts = _clear_rts,
.get_modemstatus = _get_modemstatus, .get_modemstatus = _get_modemstatus,
.set_wait_mask = _set_wait_mask,
.get_wait_mask = _get_wait_mask,
.wait_on_mask = _wait_on_mask,
}; };