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:
parent
116995f865
commit
4243928c2e
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(¤tCounters, sizeof(struct serial_icounter_struct));
|
||||||
|
if (ioctl(pComm->fd, TIOCGICOUNT, ¤tCounters) < 0)
|
||||||
|
{
|
||||||
|
DEBUG_WARN("TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno));
|
||||||
|
SetLastError(ERROR_IO_DEVICE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NB: preferred below "currentCounters.* != pComm->counters.*" over "currentCounters.* > pComm->counters.*" thinking the counters can loop */
|
||||||
|
|
||||||
|
|
||||||
|
/* events */
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_RXCHAR)
|
||||||
|
{
|
||||||
|
if (nbBytesToBeRead > 0)
|
||||||
|
{
|
||||||
|
/* at least one character is pending to be read */
|
||||||
|
*pOutputMask |= SERIAL_EV_RXCHAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_RXFLAG)
|
||||||
|
{
|
||||||
|
if (pComm->pendingEvents & SERIAL_EV_RXFLAG) // TMP: to be done in the ReadThread
|
||||||
|
{
|
||||||
|
/* the event character was received FIXME: is the character supposed to be still in the input buffer? */
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->pendingEvents &= ~SERIAL_EV_RXFLAG;
|
||||||
|
*pOutputMask |= SERIAL_EV_RXFLAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_TXEMPTY)
|
||||||
|
{
|
||||||
|
if (nbBytesToBeWritten == 0)
|
||||||
|
{
|
||||||
|
/* NB: as of today CommWriteFile still blocks and uses the same thread than CommDeviceIoControl,
|
||||||
|
* it should be enough to just check nbBytesToBeWritten
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* the output buffer is empty */
|
||||||
|
*pOutputMask |= SERIAL_EV_TXEMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_CTS)
|
||||||
|
{
|
||||||
|
tiocmiwaitMask |= TIOCM_CTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_DSR)
|
||||||
|
{
|
||||||
|
tiocmiwaitMask |= TIOCM_DSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_RLSD)
|
||||||
|
{
|
||||||
|
tiocmiwaitMask |= TIOCM_CD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_BREAK)
|
||||||
|
{
|
||||||
|
if (currentCounters.brk != pComm->counters.brk)
|
||||||
|
{
|
||||||
|
*pOutputMask |= SERIAL_EV_BREAK;
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->counters.brk = currentCounters.brk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_ERR)
|
||||||
|
{
|
||||||
|
if ((currentCounters.frame != pComm->counters.frame) ||
|
||||||
|
(currentCounters.overrun != pComm->counters.overrun) ||
|
||||||
|
(currentCounters.parity != pComm->counters.parity))
|
||||||
|
{
|
||||||
|
*pOutputMask |= SERIAL_EV_ERR;
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->counters.frame = currentCounters.frame;
|
||||||
|
pComm->counters.overrun = currentCounters.overrun;
|
||||||
|
pComm->counters.parity = currentCounters.parity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_RING)
|
||||||
|
{
|
||||||
|
tiocmiwaitMask |= TIOCM_RNG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pComm->waitMask & SERIAL_EV_RX80FULL)
|
||||||
|
{
|
||||||
|
if (nbBytesToBeRead > (0.8 * N_TTY_BUF_SIZE))
|
||||||
|
*pOutputMask |= SERIAL_EV_RX80FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*pOutputMask == 0) && /* don't need to wait more if at least an event already occured */
|
||||||
|
(tiocmiwaitMask > 0))
|
||||||
|
{
|
||||||
|
if ((pComm->waitMask & SERIAL_EV_CTS) && currentCounters.cts != pComm->counters.cts)
|
||||||
|
{
|
||||||
|
*pOutputMask |= SERIAL_EV_CTS;
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->counters.cts = currentCounters.cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pComm->waitMask & SERIAL_EV_DSR) && currentCounters.dsr != pComm->counters.dsr)
|
||||||
|
{
|
||||||
|
*pOutputMask |= SERIAL_EV_DSR;
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->counters.dsr = currentCounters.dsr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pComm->waitMask & SERIAL_EV_RLSD) && currentCounters.dcd != pComm->counters.dcd)
|
||||||
|
{
|
||||||
|
*pOutputMask |= SERIAL_EV_RLSD;
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->counters.dcd = currentCounters.dcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pComm->waitMask & SERIAL_EV_RING) && currentCounters.rng != pComm->counters.rng)
|
||||||
|
{
|
||||||
|
*pOutputMask |= SERIAL_EV_RING;
|
||||||
|
|
||||||
|
/* event consumption */
|
||||||
|
pComm->counters.rng = currentCounters.rng;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FIXME: TIOCMIWAIT could be possible if _wait_on_mask gets its own thread */
|
||||||
|
/* if (*pOutputMask == 0) */
|
||||||
|
/* { */
|
||||||
|
/* if (ioctl(pComm->fd, TIOCMIWAIT, &tiocmiwaitMask) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* DEBUG_WARN("TIOCMIWAIT ioctl failed, errno=[%d] %s", errno, strerror(errno)); */
|
||||||
|
/* SetLastError(ERROR_IO_DEVICE); */
|
||||||
|
/* return FALSE; */
|
||||||
|
/* } */
|
||||||
|
/* /\* TODO: check counters again after TIOCMIWAIT *\/ */
|
||||||
|
/* } */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pOutputMask != 0)
|
||||||
|
{
|
||||||
|
/* at least an event occurred */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_WARN("_wait_on_mask pending on events:0X%0.4X", pComm->waitMask);
|
||||||
|
SetLastError(ERROR_IO_PENDING); /* see: WaitCommEvent's help */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static REMOTE_SERIAL_DRIVER _SerialSys =
|
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user