23#include <winpr/config.h>
25#include <winpr/assert.h>
30#if defined(WINPR_HAVE_SYS_EVENTFD_H)
31#include <sys/eventfd.h>
40#include <winpr/comm.h>
41#include <winpr/tchar.h>
42#include <winpr/wlog.h>
43#include <winpr/handle.h>
45#include "comm_ioctl.h"
48#define TAG WINPR_TAG("comm")
57static wLog* sLog = NULL;
65typedef struct comm_device COMM_DEVICE;
69#define COMM_DEVICE_MAX 128
70static COMM_DEVICE** sCommDevices = NULL;
73static pthread_once_t sCommInitialized = PTHREAD_ONCE_INIT;
76 { IOCTL_SERIAL_SET_BAUD_RATE,
"IOCTL_SERIAL_SET_BAUD_RATE" },
77 { IOCTL_SERIAL_GET_BAUD_RATE,
"IOCTL_SERIAL_GET_BAUD_RATE" },
78 { IOCTL_SERIAL_SET_LINE_CONTROL,
"IOCTL_SERIAL_SET_LINE_CONTROL" },
79 { IOCTL_SERIAL_GET_LINE_CONTROL,
"IOCTL_SERIAL_GET_LINE_CONTROL" },
80 { IOCTL_SERIAL_SET_TIMEOUTS,
"IOCTL_SERIAL_SET_TIMEOUTS" },
81 { IOCTL_SERIAL_GET_TIMEOUTS,
"IOCTL_SERIAL_GET_TIMEOUTS" },
82 { IOCTL_SERIAL_GET_CHARS,
"IOCTL_SERIAL_GET_CHARS" },
83 { IOCTL_SERIAL_SET_CHARS,
"IOCTL_SERIAL_SET_CHARS" },
84 { IOCTL_SERIAL_SET_DTR,
"IOCTL_SERIAL_SET_DTR" },
85 { IOCTL_SERIAL_CLR_DTR,
"IOCTL_SERIAL_CLR_DTR" },
86 { IOCTL_SERIAL_RESET_DEVICE,
"IOCTL_SERIAL_RESET_DEVICE" },
87 { IOCTL_SERIAL_SET_RTS,
"IOCTL_SERIAL_SET_RTS" },
88 { IOCTL_SERIAL_CLR_RTS,
"IOCTL_SERIAL_CLR_RTS" },
89 { IOCTL_SERIAL_SET_XOFF,
"IOCTL_SERIAL_SET_XOFF" },
90 { IOCTL_SERIAL_SET_XON,
"IOCTL_SERIAL_SET_XON" },
91 { IOCTL_SERIAL_SET_BREAK_ON,
"IOCTL_SERIAL_SET_BREAK_ON" },
92 { IOCTL_SERIAL_SET_BREAK_OFF,
"IOCTL_SERIAL_SET_BREAK_OFF" },
93 { IOCTL_SERIAL_SET_QUEUE_SIZE,
"IOCTL_SERIAL_SET_QUEUE_SIZE" },
94 { IOCTL_SERIAL_GET_WAIT_MASK,
"IOCTL_SERIAL_GET_WAIT_MASK" },
95 { IOCTL_SERIAL_SET_WAIT_MASK,
"IOCTL_SERIAL_SET_WAIT_MASK" },
96 { IOCTL_SERIAL_WAIT_ON_MASK,
"IOCTL_SERIAL_WAIT_ON_MASK" },
97 { IOCTL_SERIAL_IMMEDIATE_CHAR,
"IOCTL_SERIAL_IMMEDIATE_CHAR" },
98 { IOCTL_SERIAL_PURGE,
"IOCTL_SERIAL_PURGE" },
99 { IOCTL_SERIAL_GET_HANDFLOW,
"IOCTL_SERIAL_GET_HANDFLOW" },
100 { IOCTL_SERIAL_SET_HANDFLOW,
"IOCTL_SERIAL_SET_HANDFLOW" },
101 { IOCTL_SERIAL_GET_MODEMSTATUS,
"IOCTL_SERIAL_GET_MODEMSTATUS" },
102 { IOCTL_SERIAL_GET_DTRRTS,
"IOCTL_SERIAL_GET_DTRRTS" },
103 { IOCTL_SERIAL_GET_COMMSTATUS,
"IOCTL_SERIAL_GET_COMMSTATUS" },
104 { IOCTL_SERIAL_GET_PROPERTIES,
"IOCTL_SERIAL_GET_PROPERTIES" },
107 { IOCTL_SERIAL_CONFIG_SIZE,
"IOCTL_SERIAL_CONFIG_SIZE" },
127 { IOCTL_USBPRINT_GET_1284_ID,
"IOCTL_USBPRINT_GET_1284_ID" }
130const char* _comm_serial_ioctl_name(ULONG number)
132 for (
size_t x = 0; x < ARRAYSIZE(S_SERIAL_IOCTL_NAMES); x++)
135 if (cur->number == number)
139 return "(unknown ioctl name)";
142static int CommGetFd(HANDLE handle)
144 WINPR_COMM* comm = (WINPR_COMM*)handle;
146 if (!CommIsHandled(handle))
154#if defined(WINPR_HAVE_SERIAL_SUPPORT)
155 static const HANDLE_CREATOR sCommHandleCreator = { .IsHandled = IsCommDevice,
156 .CreateFileA = CommCreateFileA };
157 return &sCommHandleCreator;
163static void CommInit(
void)
166 WINPR_ASSERT(sLog == NULL);
167 WINPR_ASSERT(sCommDevices == NULL);
168 sCommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX + 1,
sizeof(COMM_DEVICE*));
173 if (!InitializeCriticalSectionEx(&sCommDevicesLock, 0, 0))
175 free((
void*)sCommDevices);
180 sLog = WLog_Get(TAG);
181 WINPR_ASSERT(sLog != NULL);
188static BOOL CommInitialized(
void)
190 if (pthread_once(&sCommInitialized, CommInit) != 0)
192 SetLastError(ERROR_DLL_INIT_FAILED);
199void CommLog_PrintEx(DWORD level,
const char* file,
size_t line,
const char* fkt, ...)
201 if (!CommInitialized())
204 if (!WLog_IsLevelActive(sLog, level))
208 WLog_PrintMessageVA(sLog, WLOG_MESSAGE_TEXT, level, line, file, fkt, ap);
212BOOL BuildCommDCBA(WINPR_ATTR_UNUSED LPCSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB)
214 if (!CommInitialized())
218 CommLog_Print(WLOG_ERROR,
"Not implemented");
219 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
223BOOL BuildCommDCBW(WINPR_ATTR_UNUSED LPCWSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB)
225 if (!CommInitialized())
229 CommLog_Print(WLOG_ERROR,
"Not implemented");
230 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
234BOOL BuildCommDCBAndTimeoutsA(WINPR_ATTR_UNUSED LPCSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB,
237 if (!CommInitialized())
241 CommLog_Print(WLOG_ERROR,
"Not implemented");
242 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
246BOOL BuildCommDCBAndTimeoutsW(WINPR_ATTR_UNUSED LPCWSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB,
249 if (!CommInitialized())
253 CommLog_Print(WLOG_ERROR,
"Not implemented");
254 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
258BOOL CommConfigDialogA(WINPR_ATTR_UNUSED LPCSTR lpszName, WINPR_ATTR_UNUSED HWND hWnd,
261 if (!CommInitialized())
265 CommLog_Print(WLOG_ERROR,
"Not implemented");
266 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
270BOOL CommConfigDialogW(WINPR_ATTR_UNUSED LPCWSTR lpszName, WINPR_ATTR_UNUSED HWND hWnd,
273 if (!CommInitialized())
277 CommLog_Print(WLOG_ERROR,
"Not implemented");
278 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
282BOOL GetCommConfig(HANDLE hCommDev, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
283 WINPR_ATTR_UNUSED LPDWORD lpdwSize)
285 WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
287 if (!CommInitialized())
295 CommLog_Print(WLOG_ERROR,
"Not implemented");
296 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
300BOOL SetCommConfig(HANDLE hCommDev, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
301 WINPR_ATTR_UNUSED DWORD dwSize)
303 WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
305 if (!CommInitialized())
313 CommLog_Print(WLOG_ERROR,
"Not implemented");
314 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
318BOOL GetCommMask(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpEvtMask)
320 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
322 if (!CommInitialized())
330 CommLog_Print(WLOG_ERROR,
"Not implemented");
331 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
335BOOL SetCommMask(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwEvtMask)
337 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
339 if (!CommInitialized())
347 CommLog_Print(WLOG_ERROR,
"Not implemented");
348 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
352BOOL GetCommModemStatus(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpModemStat)
354 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
356 if (!CommInitialized())
364 CommLog_Print(WLOG_ERROR,
"Not implemented");
365 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
374BOOL GetCommProperties(HANDLE hFile,
LPCOMMPROP lpCommProp)
376 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
377 DWORD bytesReturned = 0;
379 if (!CommIsHandleValid(hFile))
382 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, lpCommProp,
383 sizeof(
COMMPROP), &bytesReturned, NULL))
385 CommLog_Print(WLOG_WARN,
"GetCommProperties failure.");
401BOOL GetCommState(HANDLE hFile,
LPDCB lpDCB)
403 DCB* lpLocalDcb = NULL;
404 struct termios currentState;
405 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
406 DWORD bytesReturned = 0;
408 if (!CommIsHandleValid(hFile))
413 SetLastError(ERROR_INVALID_DATA);
417 if (lpDCB->DCBlength <
sizeof(
DCB))
419 SetLastError(ERROR_INVALID_DATA);
423 if (tcgetattr(pComm->fd, ¤tState) < 0)
425 SetLastError(ERROR_IO_DEVICE);
429 lpLocalDcb = (
DCB*)calloc(1, lpDCB->DCBlength);
431 if (lpLocalDcb == NULL)
433 SetLastError(ERROR_OUTOFMEMORY);
438 lpLocalDcb->DCBlength = lpDCB->DCBlength;
441 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &baudRate,
444 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the baud rate.");
448 lpLocalDcb->BaudRate = baudRate.BaudRate;
449 lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0;
451 if (!lpLocalDcb->fBinary)
453 CommLog_Print(WLOG_WARN,
"Unexpected nonbinary mode, consider to unset the ICANON flag.");
456 lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0;
459 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow,
462 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the handflow settings.");
466 lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0;
467 lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0;
469 if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
471 lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
473 else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL)
475 lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE;
479 lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE;
482 lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0;
483 lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0;
484 lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0;
485 lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0;
486 lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0;
487 lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0;
489 if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
491 lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
493 else if (handflow.FlowReplace & SERIAL_RTS_CONTROL)
495 lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE;
499 lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE;
504 lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0;
506 lpLocalDcb->wReserved = 0;
507 lpLocalDcb->XonLim = WINPR_ASSERTING_INT_CAST(WORD, handflow.XonLimit);
508 lpLocalDcb->XoffLim = WINPR_ASSERTING_INT_CAST(WORD, handflow.XoffLimit);
511 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl,
514 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the control settings.");
518 lpLocalDcb->ByteSize = lineControl.WordLength;
519 lpLocalDcb->Parity = lineControl.Parity;
520 lpLocalDcb->StopBits = lineControl.StopBits;
523 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars,
526 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the serial chars.");
530 lpLocalDcb->XonChar = serialChars.XonChar;
531 lpLocalDcb->XoffChar = serialChars.XoffChar;
532 lpLocalDcb->ErrorChar = serialChars.ErrorChar;
533 lpLocalDcb->EofChar = serialChars.EofChar;
534 lpLocalDcb->EvtChar = serialChars.EventChar;
535 memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength);
554BOOL SetCommState(HANDLE hFile,
LPDCB lpDCB)
556 struct termios upcomingTermios = { 0 };
557 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
558 DWORD bytesReturned = 0;
562 if (!CommIsHandleValid(hFile))
567 SetLastError(ERROR_INVALID_DATA);
575 baudRate.BaudRate = lpDCB->BaudRate;
577 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate,
sizeof(
SERIAL_BAUD_RATE),
578 NULL, 0, &bytesReturned, NULL))
580 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the baud rate.");
586 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars,
590 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not get the initial serial chars.");
594 serialChars.XonChar = lpDCB->XonChar;
595 serialChars.XoffChar = lpDCB->XoffChar;
596 serialChars.ErrorChar = lpDCB->ErrorChar;
597 serialChars.EofChar = lpDCB->EofChar;
598 serialChars.EventChar = lpDCB->EvtChar;
600 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars,
sizeof(
SERIAL_CHARS),
601 NULL, 0, &bytesReturned, NULL))
603 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the serial chars.");
608 lineControl.StopBits = lpDCB->StopBits;
609 lineControl.Parity = lpDCB->Parity;
610 lineControl.WordLength = lpDCB->ByteSize;
612 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_LINE_CONTROL, &lineControl,
615 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the control settings.");
621 if (lpDCB->fOutxCtsFlow)
623 handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
626 if (lpDCB->fOutxDsrFlow)
628 handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
631 switch (lpDCB->fDtrControl)
633 case SERIAL_DTR_HANDSHAKE:
634 handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE;
637 case SERIAL_DTR_CONTROL:
638 handflow.ControlHandShake |= DTR_CONTROL_ENABLE;
641 case DTR_CONTROL_DISABLE:
646 CommLog_Print(WLOG_WARN,
"Unexpected fDtrControl value: %" PRIu32
"\n",
651 if (lpDCB->fDsrSensitivity)
653 handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
656 if (lpDCB->fTXContinueOnXoff)
658 handflow.FlowReplace |= SERIAL_XOFF_CONTINUE;
663 handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
668 handflow.FlowReplace |= SERIAL_AUTO_RECEIVE;
671 if (lpDCB->fErrorChar)
673 handflow.FlowReplace |= SERIAL_ERROR_CHAR;
678 handflow.FlowReplace |= SERIAL_NULL_STRIPPING;
681 switch (lpDCB->fRtsControl)
683 case RTS_CONTROL_TOGGLE:
684 CommLog_Print(WLOG_WARN,
"Unsupported RTS_CONTROL_TOGGLE feature");
688 case RTS_CONTROL_HANDSHAKE:
689 handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
692 case RTS_CONTROL_ENABLE:
693 handflow.FlowReplace |= SERIAL_RTS_CONTROL;
696 case RTS_CONTROL_DISABLE:
701 CommLog_Print(WLOG_WARN,
"Unexpected fRtsControl value: %" PRIu32
"\n",
706 if (lpDCB->fAbortOnError)
708 handflow.ControlHandShake |= SERIAL_ERROR_ABORT;
713 handflow.XonLimit = lpDCB->XonLim;
714 handflow.XoffLimit = lpDCB->XoffLim;
716 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow,
sizeof(
SERIAL_HANDFLOW),
717 NULL, 0, &bytesReturned, NULL))
719 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the handflow settings.");
725 if (tcgetattr(pComm->fd, &upcomingTermios) <
728 SetLastError(ERROR_IO_DEVICE);
734 upcomingTermios.c_lflag &= (tcflag_t)~ICANON;
738 upcomingTermios.c_lflag |= ICANON;
739 CommLog_Print(WLOG_WARN,
"Unexpected nonbinary mode, consider to unset the ICANON flag.");
744 upcomingTermios.c_iflag |= INPCK;
748 upcomingTermios.c_iflag &= (tcflag_t)~INPCK;
762 if (comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
764 SetLastError(ERROR_IO_DEVICE);
777 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
778 DWORD bytesReturned = 0;
780 if (!CommIsHandleValid(hFile))
785 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, lpCommTimeouts,
788 CommLog_Print(WLOG_WARN,
"GetCommTimeouts failure.");
801 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
802 DWORD bytesReturned = 0;
804 if (!CommIsHandleValid(hFile))
809 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_TIMEOUTS, lpCommTimeouts,
sizeof(
COMMTIMEOUTS),
810 NULL, 0, &bytesReturned, NULL))
812 CommLog_Print(WLOG_WARN,
"SetCommTimeouts failure.");
819BOOL GetDefaultCommConfigA(WINPR_ATTR_UNUSED LPCSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
820 WINPR_ATTR_UNUSED LPDWORD lpdwSize)
822 if (!CommInitialized())
826 CommLog_Print(WLOG_ERROR,
"Not implemented");
827 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
831BOOL GetDefaultCommConfigW(WINPR_ATTR_UNUSED LPCWSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
832 WINPR_ATTR_UNUSED LPDWORD lpdwSize)
834 if (!CommInitialized())
838 CommLog_Print(WLOG_ERROR,
"Not implemented");
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
843BOOL SetDefaultCommConfigA(WINPR_ATTR_UNUSED LPCSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
844 WINPR_ATTR_UNUSED DWORD dwSize)
846 if (!CommInitialized())
850 CommLog_Print(WLOG_ERROR,
"Not implemented");
851 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
855BOOL SetDefaultCommConfigW(WINPR_ATTR_UNUSED LPCWSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
856 WINPR_ATTR_UNUSED DWORD dwSize)
858 if (!CommInitialized())
862 CommLog_Print(WLOG_ERROR,
"Not implemented");
863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
867BOOL SetCommBreak(HANDLE hFile)
869 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
871 if (!CommInitialized())
879 CommLog_Print(WLOG_ERROR,
"Not implemented");
880 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
884BOOL ClearCommBreak(HANDLE hFile)
886 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
888 if (!CommInitialized())
896 CommLog_Print(WLOG_ERROR,
"Not implemented");
897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
901BOOL ClearCommError(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpErrors,
904 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
906 if (!CommInitialized())
914 CommLog_Print(WLOG_ERROR,
"Not implemented");
915 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
919BOOL PurgeComm(HANDLE hFile, DWORD dwFlags)
921 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
922 DWORD bytesReturned = 0;
924 if (!CommIsHandleValid(hFile))
927 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_PURGE, &dwFlags,
sizeof(DWORD), NULL, 0,
928 &bytesReturned, NULL))
930 CommLog_Print(WLOG_WARN,
"PurgeComm failure.");
937BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue)
939 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
941 DWORD bytesReturned = 0;
943 if (!CommIsHandleValid(hFile))
946 queueSize.InSize = dwInQueue;
947 queueSize.OutSize = dwOutQueue;
949 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_QUEUE_SIZE, &queueSize,
952 CommLog_Print(WLOG_WARN,
"SetCommTimeouts failure.");
959BOOL EscapeCommFunction(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwFunc)
961 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
963 if (!CommInitialized())
971 CommLog_Print(WLOG_ERROR,
"Not implemented");
972 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
976BOOL TransmitCommChar(HANDLE hFile, WINPR_ATTR_UNUSED
char cChar)
978 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
980 if (!CommInitialized())
988 CommLog_Print(WLOG_ERROR,
"Not implemented");
989 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
993BOOL WaitCommEvent(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpEvtMask,
996 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
998 if (!CommInitialized())
1006 CommLog_Print(WLOG_ERROR,
"Not implemented");
1007 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1020BOOL DefineCommDevice( LPCTSTR lpDeviceName, LPCTSTR lpTargetPath)
1022 LPTSTR storedDeviceName = NULL;
1023 LPTSTR storedTargetPath = NULL;
1025 if (!CommInitialized())
1028 EnterCriticalSection(&sCommDevicesLock);
1030 if (sCommDevices == NULL)
1032 SetLastError(ERROR_DLL_INIT_FAILED);
1036 storedDeviceName = _tcsdup(lpDeviceName);
1038 if (storedDeviceName == NULL)
1040 SetLastError(ERROR_OUTOFMEMORY);
1044 storedTargetPath = _tcsdup(lpTargetPath);
1046 if (storedTargetPath == NULL)
1048 SetLastError(ERROR_OUTOFMEMORY);
1053 for (; i < COMM_DEVICE_MAX; i++)
1055 if (sCommDevices[i] != NULL)
1057 if (_tcscmp(sCommDevices[i]->name, storedDeviceName) == 0)
1060 free(sCommDevices[i]->name);
1061 free(sCommDevices[i]->path);
1062 sCommDevices[i]->name = storedDeviceName;
1063 sCommDevices[i]->path = storedTargetPath;
1070 sCommDevices[i] = (COMM_DEVICE*)calloc(1,
sizeof(COMM_DEVICE));
1072 if (sCommDevices[i] == NULL)
1074 SetLastError(ERROR_OUTOFMEMORY);
1078 sCommDevices[i]->name = storedDeviceName;
1079 sCommDevices[i]->path = storedTargetPath;
1084 if (i == COMM_DEVICE_MAX)
1086 SetLastError(ERROR_OUTOFMEMORY);
1090 LeaveCriticalSection(&sCommDevicesLock);
1093 free(storedDeviceName);
1094 free(storedTargetPath);
1095 LeaveCriticalSection(&sCommDevicesLock);
1115DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax)
1117 LPTSTR storedTargetPath = NULL;
1118 SetLastError(ERROR_SUCCESS);
1120 if (!CommInitialized())
1123 if (sCommDevices == NULL)
1125 SetLastError(ERROR_DLL_INIT_FAILED);
1129 if (lpDeviceName == NULL || lpTargetPath == NULL)
1131 SetLastError(ERROR_NOT_SUPPORTED);
1135 EnterCriticalSection(&sCommDevicesLock);
1136 storedTargetPath = NULL;
1138 for (
int i = 0; i < COMM_DEVICE_MAX; i++)
1140 if (sCommDevices[i] != NULL)
1142 if (_tcscmp(sCommDevices[i]->name, lpDeviceName) == 0)
1144 storedTargetPath = sCommDevices[i]->path;
1154 LeaveCriticalSection(&sCommDevicesLock);
1156 if (storedTargetPath == NULL)
1158 SetLastError(ERROR_INVALID_DATA);
1162 const size_t size = _tcsnlen(storedTargetPath, ucchMax);
1163 if (size + 2 > ucchMax)
1165 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1169 _tcsncpy(lpTargetPath, storedTargetPath, size + 1);
1170 lpTargetPath[size + 2] =
'\0';
1171 return (DWORD)size + 2UL;
1177BOOL IsCommDevice(LPCTSTR lpDeviceName)
1179 TCHAR lpTargetPath[MAX_PATH];
1181 if (!CommInitialized())
1184 if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0)
1195void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID driverId)
1199 WINPR_COMM* pComm = NULL;
1201 if (!CommInitialized())
1204 if (!winpr_Handle_GetInfo(hComm, &Type, &Object))
1206 CommLog_Print(WLOG_WARN,
"_comm_setServerSerialDriver failure");
1210 pComm = (WINPR_COMM*)Object;
1211 pComm->serverSerialDriverId = driverId;
1214static HANDLE_OPS ops = { CommIsHandled, CommCloseHandle,
1251HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode,
1252 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1253 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1255 CHAR devicePath[MAX_PATH] = { 0 };
1256 struct stat deviceStat = { 0 };
1257 WINPR_COMM* pComm = NULL;
1258 struct termios upcomingTermios = { 0 };
1260 if (!CommInitialized())
1261 return INVALID_HANDLE_VALUE;
1263 if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE))
1265 CommLog_Print(WLOG_WARN,
"unexpected access to the device: 0x%08" PRIX32
"",
1269 if (dwShareMode != 0)
1271 SetLastError(ERROR_SHARING_VIOLATION);
1272 return INVALID_HANDLE_VALUE;
1278 if (lpSecurityAttributes != NULL)
1280 CommLog_Print(WLOG_WARN,
"unexpected security attributes, nLength=%" PRIu32
"",
1281 lpSecurityAttributes->nLength);
1284 if (dwCreationDisposition != OPEN_EXISTING)
1286 SetLastError(ERROR_FILE_NOT_FOUND);
1287 return INVALID_HANDLE_VALUE;
1290 if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0)
1293 return INVALID_HANDLE_VALUE;
1296 if (stat(devicePath, &deviceStat) < 0)
1298 CommLog_Print(WLOG_WARN,
"device not found %s", devicePath);
1299 SetLastError(ERROR_FILE_NOT_FOUND);
1300 return INVALID_HANDLE_VALUE;
1303 if (!S_ISCHR(deviceStat.st_mode))
1305 CommLog_Print(WLOG_WARN,
"bad device %s", devicePath);
1306 SetLastError(ERROR_BAD_DEVICE);
1307 return INVALID_HANDLE_VALUE;
1310 if (dwFlagsAndAttributes != 0)
1312 CommLog_Print(WLOG_WARN,
"unexpected flags and attributes: 0x%08" PRIX32
"",
1313 dwFlagsAndAttributes);
1316 if (hTemplateFile != NULL)
1318 SetLastError(ERROR_NOT_SUPPORTED);
1319 return INVALID_HANDLE_VALUE;
1322 pComm = (WINPR_COMM*)calloc(1,
sizeof(WINPR_COMM));
1326 SetLastError(ERROR_OUTOFMEMORY);
1327 return INVALID_HANDLE_VALUE;
1330 WINPR_HANDLE_SET_TYPE_AND_MODE(pComm, HANDLE_TYPE_COMM, WINPR_FD_READ);
1331 pComm->common.ops = &ops;
1333 pComm->fd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
1337 CommLog_Print(WLOG_WARN,
"failed to open device %s", devicePath);
1338 SetLastError(ERROR_BAD_DEVICE);
1342 pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK);
1344 if (pComm->fd_read < 0)
1346 CommLog_Print(WLOG_WARN,
"failed to open fd_read, device: %s", devicePath);
1347 SetLastError(ERROR_BAD_DEVICE);
1351#if defined(WINPR_HAVE_SYS_EVENTFD_H)
1352 pComm->fd_read_event = eventfd(
1356 if (pComm->fd_read_event < 0)
1358 CommLog_Print(WLOG_WARN,
"failed to open fd_read_event, device: %s", devicePath);
1359 SetLastError(ERROR_BAD_DEVICE);
1363 InitializeCriticalSection(&pComm->ReadLock);
1364 pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK);
1366 if (pComm->fd_write < 0)
1368 CommLog_Print(WLOG_WARN,
"failed to open fd_write, device: %s", devicePath);
1369 SetLastError(ERROR_BAD_DEVICE);
1373#if defined(WINPR_HAVE_SYS_EVENTFD_H)
1374 pComm->fd_write_event = eventfd(
1378 if (pComm->fd_write_event < 0)
1380 CommLog_Print(WLOG_WARN,
"failed to open fd_write_event, device: %s", devicePath);
1381 SetLastError(ERROR_BAD_DEVICE);
1385 InitializeCriticalSection(&pComm->WriteLock);
1387 pComm->serverSerialDriverId = SerialDriverUnknown;
1388 InitializeCriticalSection(&pComm->EventsLock);
1390 (void)CommUpdateIOCount(pComm, TRUE);
1395 ZeroMemory(&upcomingTermios,
sizeof(
struct termios));
1397 if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
1399 SetLastError(ERROR_IO_DEVICE);
1403 upcomingTermios.c_iflag &=
1404 (tcflag_t) ~( BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL );
1405 upcomingTermios.c_oflag = 0;
1406 upcomingTermios.c_lflag = 0;
1415 upcomingTermios.c_cflag |= CLOCAL | CREAD;
1417 if (comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
1419 SetLastError(ERROR_IO_DEVICE);
1423 return (HANDLE)pComm;
1425 WINPR_PRAGMA_DIAG_PUSH
1426 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC(
void) CloseHandle(pComm);
1427 WINPR_PRAGMA_DIAG_POP
1428 return INVALID_HANDLE_VALUE;
1431BOOL CommIsHandled(HANDLE handle)
1433 if (!CommInitialized())
1436 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_COMM, TRUE);
1439BOOL CommIsHandleValid(HANDLE handle)
1441 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1442 if (!CommIsHandled(handle))
1446 SetLastError(ERROR_INVALID_HANDLE);
1452BOOL CommCloseHandle(HANDLE handle)
1454 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1456 if (!CommIsHandled(handle))
1459 DeleteCriticalSection(&pComm->ReadLock);
1460 DeleteCriticalSection(&pComm->WriteLock);
1461 DeleteCriticalSection(&pComm->EventsLock);
1466 if (pComm->fd_write > 0)
1467 close(pComm->fd_write);
1469 if (pComm->fd_write_event > 0)
1470 close(pComm->fd_write_event);
1472 if (pComm->fd_read > 0)
1473 close(pComm->fd_read);
1475 if (pComm->fd_read_event > 0)
1476 close(pComm->fd_read_event);
1482#if defined(WINPR_HAVE_SYS_EVENTFD_H)
1483#ifndef WITH_EVENTFD_READ_WRITE
1484int eventfd_read(
int fd, eventfd_t* value)
1486 return (read(fd, value,
sizeof(*value)) ==
sizeof(*value)) ? 0 : -1;
1489int eventfd_write(
int fd, eventfd_t value)
1491 return (write(fd, &value,
sizeof(value)) ==
sizeof(value)) ? 0 : -1;
1496static const char* CommIoCtlToStr(
unsigned long int io)
1500#if defined(WINPR_HAVE_SERIAL_SUPPORT)
1545#if defined(TIOCEXCL)
1549#if defined(TIOCNXCL)
1553#if defined(TIOCSCTTY)
1557#if defined(TIOCGPGRP)
1561#if defined(TIOCSPGRP)
1565#if defined(TIOCOUTQ)
1573#if defined(TIOCGWINSZ)
1575 return "TIOCGWINSZ";
1577#if defined(TIOCSWINSZ)
1579 return "TIOCSWINSZ";
1581#if defined(TIOCMGET)
1585#if defined(TIOCMBIS)
1589#if defined(TIOCMBIC)
1593#if defined(TIOCMSET)
1597#if defined(TIOCGSOFTCAR)
1599 return "TIOCGSOFTCAR";
1601#if defined(TIOCSSOFTCAR)
1603 return "TIOCSSOFTCAR";
1605#if defined(FIONREAD)
1607 return "FIONREAD/TIOCINQ";
1609#if defined(TIOCLINUX)
1613#if defined(TIOCCONS)
1617#if defined(TIOCGSERIAL)
1619 return "TIOCGSERIAL";
1621#if defined(TIOCSSERIAL)
1623 return "TIOCSSERIAL";
1633#if defined(TIOCNOTTY)
1637#if defined(TIOCSETD)
1641#if defined(TIOCGETD)
1649#if defined(TIOCSBRK)
1653#if defined(TIOCCBRK)
1657#if defined(TIOCGSID)
1661#if defined(TIOCGRS485)
1663 return "TIOCGRS485";
1665#if defined(TIOCSRS485)
1667 return "TIOCSRS485";
1669#if defined(TIOCSPTLCK)
1671 return "TIOCSPTLCK";
1693#if defined(TIOCVHANGUP)
1695 return "TIOCVHANGUP";
1697#if defined(TIOCGPTPEER)
1699 return "TIOCGPTPEER";
1701#if defined(FIONCLEX)
1709#if defined(FIOASYNC)
1713#if defined(TIOCSERCONFIG)
1715 return "TIOCSERCONFIG";
1717#if defined(TIOCSERGWILD)
1719 return "TIOCSERGWILD";
1721#if defined(TIOCSERSWILD)
1723 return "TIOCSERSWILD";
1725#if defined(TIOCGLCKTRMIOS)
1726 case TIOCGLCKTRMIOS:
1727 return "TIOCGLCKTRMIOS";
1729#if defined(TIOCSLCKTRMIOS)
1730 case TIOCSLCKTRMIOS:
1731 return "TIOCSLCKTRMIOS";
1733#if defined(TIOCSERGSTRUCT)
1734 case TIOCSERGSTRUCT:
1735 return "TIOCSERGSTRUCT";
1737#if defined(TIOCSERGETLSR)
1739 return "TIOCSERGETLSR";
1741#if defined(TIOCSERGETMULTI)
1742 case TIOCSERGETMULTI:
1743 return "TIOCSERGETMULTI";
1745#if defined(TIOCSERSETMULTI)
1746 case TIOCSERSETMULTI:
1747 return "TIOCSERSETMULTI";
1749#if defined(TIOCMIWAIT)
1751 return "TIOCMIWAIT";
1753#if defined(TIOCGICOUNT)
1755 return "TIOCGICOUNT";
1757#if defined(FIOQSIZE)
1761#if defined(TIOCPKT_DATA)
1763 return "TIOCPKT_DATA";
1765#if defined(TIOCPKT_FLUSHWRITE)
1766 case TIOCPKT_FLUSHWRITE:
1767 return "TIOCPKT_FLUSHWRITE";
1769#if defined(TIOCPKT_STOP)
1771 return "TIOCPKT_STOP";
1773#if defined(TIOCPKT_START)
1775 return "TIOCPKT_START";
1777#if defined(TIOCPKT_NOSTOP)
1778 case TIOCPKT_NOSTOP:
1779 return "TIOCPKT_NOSTOP";
1781#if defined(TIOCPKT_DOSTOP)
1782 case TIOCPKT_DOSTOP:
1783 return "TIOCPKT_DOSTOP";
1785#if defined(TIOCPKT_IOCTL)
1787 return "TIOCPKT_IOCTL";
1795static BOOL CommStatusErrorEx(WINPR_COMM* pComm,
unsigned long int ctl,
const char* file,
1796 const char* fkt,
size_t line)
1798 WINPR_ASSERT(pComm);
1799 BOOL rc = pComm->permissive ? TRUE : FALSE;
1800 const DWORD level = rc ? WLOG_DEBUG : WLOG_WARN;
1801 char ebuffer[256] = { 0 };
1802 const char* str = CommIoCtlToStr(ctl);
1804 if (CommInitialized())
1806 if (WLog_IsLevelActive(sLog, level))
1808 WLog_PrintMessage(sLog, WLOG_MESSAGE_TEXT, level, line, file, fkt,
1809 "%s [0x%08" PRIx32
"] ioctl failed, errno=[%d] %s.", str, ctl, errno,
1810 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
1815 SetLastError(ERROR_IO_DEVICE);
1820BOOL CommIoCtl_int(WINPR_COMM* pComm,
unsigned long int ctl,
void* data,
const char* file,
1821 const char* fkt,
size_t line)
1823 if (ioctl(pComm->fd, ctl, data) < 0)
1825 if (!CommStatusErrorEx(pComm, ctl, file, fkt, line))
1831BOOL CommUpdateIOCount(WINPR_ATTR_UNUSED HANDLE handle, WINPR_ATTR_UNUSED BOOL checkSupportStatus)
1833 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1834 WINPR_ASSERT(pComm);
1836#if defined(WINPR_HAVE_COMM_COUNTERS)
1837 ZeroMemory(&(pComm->counters),
sizeof(
struct serial_icounter_struct));
1838 if (pComm->TIOCGICOUNTSupported || checkSupportStatus)
1840 const int rc = ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters));
1841 if (checkSupportStatus)
1842 pComm->TIOCGICOUNTSupported = rc >= 0;
1845 if (!CommStatusErrorEx(pComm, TIOCGICOUNT, __FILE__, __func__, __LINE__))
1853static const char* CommSerialEvFlagString(ULONG flag)
1857 case SERIAL_EV_RXCHAR:
1858 return "SERIAL_EV_RXCHAR";
1859 case SERIAL_EV_RXFLAG:
1860 return "SERIAL_EV_RXFLAG";
1861 case SERIAL_EV_TXEMPTY:
1862 return "SERIAL_EV_TXEMPTY";
1864 return "SERIAL_EV_CTS ";
1866 return "SERIAL_EV_DSR ";
1867 case SERIAL_EV_RLSD:
1868 return "SERIAL_EV_RLSD";
1869 case SERIAL_EV_BREAK:
1870 return "SERIAL_EV_BREAK";
1872 return "SERIAL_EV_ERR ";
1873 case SERIAL_EV_RING:
1874 return "SERIAL_EV_RING";
1875 case SERIAL_EV_PERR:
1876 return "SERIAL_EV_PERR";
1877 case SERIAL_EV_RX80FULL:
1878 return "SERIAL_EV_RX80FULL";
1879 case SERIAL_EV_EVENT1:
1880 return "SERIAL_EV_EVENT1";
1881 case SERIAL_EV_EVENT2:
1882 return "SERIAL_EV_EVENT2";
1883 case SERIAL_EV_WINPR_WAITING:
1884 return "SERIAL_EV_WINPR_WAITING";
1885 case SERIAL_EV_WINPR_STOP:
1886 return "SERIAL_EV_WINPR_STOP";
1888 return "SERIAL_EV_UNKNOWN";
1892const char* CommSerialEvString(ULONG status,
char* buffer,
size_t size)
1894 const ULONG flags[] = { SERIAL_EV_RXCHAR, SERIAL_EV_RXFLAG, SERIAL_EV_TXEMPTY,
1895 SERIAL_EV_CTS, SERIAL_EV_DSR, SERIAL_EV_RLSD,
1896 SERIAL_EV_BREAK, SERIAL_EV_ERR, SERIAL_EV_RING,
1897 SERIAL_EV_PERR, SERIAL_EV_RX80FULL, SERIAL_EV_EVENT1,
1898 SERIAL_EV_EVENT2, SERIAL_EV_WINPR_WAITING, SERIAL_EV_WINPR_STOP };
1900 winpr_str_append(
"{", buffer, size,
"");
1902 const char* sep =
"";
1903 for (
size_t x = 0; x < ARRAYSIZE(flags); x++)
1905 const ULONG flag = flags[x];
1908 winpr_str_append(CommSerialEvFlagString(flag), buffer, size, sep);
1913 char number[32] = { 0 };
1914 (void)_snprintf(number,
sizeof(number),
"}[0x%08" PRIx32
"]", status);
1915 winpr_str_append(number, buffer, size,
"");