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 =
nullptr;
65typedef struct comm_device COMM_DEVICE;
69#define COMM_DEVICE_MAX 128
70static COMM_DEVICE** sCommDevices =
nullptr;
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 ==
nullptr);
167 WINPR_ASSERT(sCommDevices ==
nullptr);
168 sCommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX + 1,
sizeof(COMM_DEVICE*));
173 if (!InitializeCriticalSectionEx(&sCommDevicesLock, 0, 0))
175 free((
void*)sCommDevices);
176 sCommDevices =
nullptr;
180 sLog = WLog_Get(TAG);
181 WINPR_ASSERT(sLog !=
nullptr);
188static BOOL CommInitialized(
void)
190 if (pthread_once(&sCommInitialized, CommInit) != 0)
192 SetLastError(ERROR_DLL_INIT_FAILED);
199WINPR_ATTR_FORMAT_ARG(5, 6)
200void CommLog_PrintEx(DWORD level, const
char* file,
size_t line, const
char* fkt,
201 WINPR_FORMAT_ARG const
char* fmt, ...)
203 if (!CommInitialized())
206 if (!WLog_IsLevelActive(sLog, level))
208 va_list ap = WINPR_C_ARRAY_INIT;
210 WLog_PrintTextMessageVA(sLog, level, line, file, fkt, fmt, ap);
214BOOL BuildCommDCBA(WINPR_ATTR_UNUSED LPCSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB)
216 if (!CommInitialized())
220 CommLog_Print(WLOG_ERROR,
"Not implemented");
221 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
225BOOL BuildCommDCBW(WINPR_ATTR_UNUSED LPCWSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB)
227 if (!CommInitialized())
231 CommLog_Print(WLOG_ERROR,
"Not implemented");
232 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
236BOOL BuildCommDCBAndTimeoutsA(WINPR_ATTR_UNUSED LPCSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB,
239 if (!CommInitialized())
243 CommLog_Print(WLOG_ERROR,
"Not implemented");
244 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
248BOOL BuildCommDCBAndTimeoutsW(WINPR_ATTR_UNUSED LPCWSTR lpDef, WINPR_ATTR_UNUSED
LPDCB lpDCB,
251 if (!CommInitialized())
255 CommLog_Print(WLOG_ERROR,
"Not implemented");
256 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
260BOOL CommConfigDialogA(WINPR_ATTR_UNUSED LPCSTR lpszName, WINPR_ATTR_UNUSED HWND hWnd,
263 if (!CommInitialized())
267 CommLog_Print(WLOG_ERROR,
"Not implemented");
268 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
272BOOL CommConfigDialogW(WINPR_ATTR_UNUSED LPCWSTR lpszName, WINPR_ATTR_UNUSED HWND hWnd,
275 if (!CommInitialized())
279 CommLog_Print(WLOG_ERROR,
"Not implemented");
280 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
284BOOL GetCommConfig(HANDLE hCommDev, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
285 WINPR_ATTR_UNUSED LPDWORD lpdwSize)
287 WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
289 if (!CommInitialized())
297 CommLog_Print(WLOG_ERROR,
"Not implemented");
298 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
302BOOL SetCommConfig(HANDLE hCommDev, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
303 WINPR_ATTR_UNUSED DWORD dwSize)
305 WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
307 if (!CommInitialized())
315 CommLog_Print(WLOG_ERROR,
"Not implemented");
316 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
320BOOL GetCommMask(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpEvtMask)
322 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
324 if (!CommInitialized())
332 CommLog_Print(WLOG_ERROR,
"Not implemented");
333 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
337BOOL SetCommMask(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwEvtMask)
339 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
341 if (!CommInitialized())
349 CommLog_Print(WLOG_ERROR,
"Not implemented");
350 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
354BOOL GetCommModemStatus(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpModemStat)
356 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
358 if (!CommInitialized())
366 CommLog_Print(WLOG_ERROR,
"Not implemented");
367 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
376BOOL GetCommProperties(HANDLE hFile,
LPCOMMPROP lpCommProp)
378 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
379 DWORD bytesReturned = 0;
381 if (!CommIsHandleValid(hFile))
384 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_PROPERTIES,
nullptr, 0, lpCommProp,
385 sizeof(
COMMPROP), &bytesReturned,
nullptr))
387 CommLog_Print(WLOG_WARN,
"GetCommProperties failure.");
403BOOL GetCommState(HANDLE hFile,
LPDCB lpDCB)
405 DCB* lpLocalDcb =
nullptr;
406 struct termios currentState;
407 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
408 DWORD bytesReturned = 0;
410 if (!CommIsHandleValid(hFile))
415 SetLastError(ERROR_INVALID_DATA);
419 if (lpDCB->DCBlength <
sizeof(
DCB))
421 SetLastError(ERROR_INVALID_DATA);
425 if (tcgetattr(pComm->fd, ¤tState) < 0)
427 SetLastError(ERROR_IO_DEVICE);
431 lpLocalDcb = (
DCB*)calloc(1, lpDCB->DCBlength);
433 if (lpLocalDcb ==
nullptr)
435 SetLastError(ERROR_OUTOFMEMORY);
440 lpLocalDcb->DCBlength = lpDCB->DCBlength;
443 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE,
nullptr, 0, &baudRate,
446 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the baud rate.");
450 lpLocalDcb->BaudRate = baudRate.BaudRate;
451 lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0;
453 if (!lpLocalDcb->fBinary)
455 CommLog_Print(WLOG_WARN,
"Unexpected nonbinary mode, consider to unset the ICANON flag.");
458 lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0;
461 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW,
nullptr, 0, &handflow,
464 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the handflow settings.");
468 lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0;
469 lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0;
471 if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
473 lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
475 else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL)
477 lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE;
481 lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE;
484 lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0;
485 lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0;
486 lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0;
487 lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0;
488 lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0;
489 lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0;
491 if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
493 lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
495 else if (handflow.FlowReplace & SERIAL_RTS_CONTROL)
497 lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE;
501 lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE;
506 lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0;
508 lpLocalDcb->wReserved = 0;
509 lpLocalDcb->XonLim = WINPR_ASSERTING_INT_CAST(WORD, handflow.XonLimit);
510 lpLocalDcb->XoffLim = WINPR_ASSERTING_INT_CAST(WORD, handflow.XoffLimit);
515 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL,
nullptr, 0, &lineControl,
518 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the control settings.");
522 lpLocalDcb->ByteSize = lineControl.WordLength;
523 lpLocalDcb->Parity = lineControl.Parity;
524 lpLocalDcb->StopBits = lineControl.StopBits;
530 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS,
nullptr, 0, &serialChars,
533 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the serial chars.");
537 lpLocalDcb->XonChar = serialChars.XonChar;
538 lpLocalDcb->XoffChar = serialChars.XoffChar;
539 lpLocalDcb->ErrorChar = serialChars.ErrorChar;
540 lpLocalDcb->EofChar = serialChars.EofChar;
541 lpLocalDcb->EvtChar = serialChars.EventChar;
543 memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength);
562BOOL SetCommState(HANDLE hFile,
LPDCB lpDCB)
564 struct termios upcomingTermios = WINPR_C_ARRAY_INIT;
565 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
566 DWORD bytesReturned = 0;
570 if (!CommIsHandleValid(hFile))
575 SetLastError(ERROR_INVALID_DATA);
583 baudRate.BaudRate = lpDCB->BaudRate;
585 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate,
sizeof(
SERIAL_BAUD_RATE),
586 nullptr, 0, &bytesReturned,
nullptr))
588 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the baud rate.");
594 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS,
nullptr, 0, &serialChars,
598 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not get the initial serial chars.");
602 serialChars.XonChar = lpDCB->XonChar;
603 serialChars.XoffChar = lpDCB->XoffChar;
604 serialChars.ErrorChar = lpDCB->ErrorChar;
605 serialChars.EofChar = lpDCB->EofChar;
606 serialChars.EventChar = lpDCB->EvtChar;
608 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars,
sizeof(
SERIAL_CHARS),
609 nullptr, 0, &bytesReturned,
nullptr))
611 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the serial chars.");
616 lineControl.StopBits = lpDCB->StopBits;
617 lineControl.Parity = lpDCB->Parity;
618 lineControl.WordLength = lpDCB->ByteSize;
620 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_LINE_CONTROL, &lineControl,
623 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the control settings.");
629 if (lpDCB->fOutxCtsFlow)
631 handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
634 if (lpDCB->fOutxDsrFlow)
636 handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
639 switch (lpDCB->fDtrControl)
641 case SERIAL_DTR_HANDSHAKE:
642 handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE;
645 case SERIAL_DTR_CONTROL:
646 handflow.ControlHandShake |= DTR_CONTROL_ENABLE;
649 case DTR_CONTROL_DISABLE:
654 CommLog_Print(WLOG_WARN,
"Unexpected fDtrControl value: %" PRId32
"\n",
659 if (lpDCB->fDsrSensitivity)
661 handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
664 if (lpDCB->fTXContinueOnXoff)
666 handflow.FlowReplace |= SERIAL_XOFF_CONTINUE;
671 handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
676 handflow.FlowReplace |= SERIAL_AUTO_RECEIVE;
679 if (lpDCB->fErrorChar)
681 handflow.FlowReplace |= SERIAL_ERROR_CHAR;
686 handflow.FlowReplace |= SERIAL_NULL_STRIPPING;
689 switch (lpDCB->fRtsControl)
691 case RTS_CONTROL_TOGGLE:
692 CommLog_Print(WLOG_WARN,
"Unsupported RTS_CONTROL_TOGGLE feature");
696 case RTS_CONTROL_HANDSHAKE:
697 handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
700 case RTS_CONTROL_ENABLE:
701 handflow.FlowReplace |= SERIAL_RTS_CONTROL;
704 case RTS_CONTROL_DISABLE:
709 CommLog_Print(WLOG_WARN,
"Unexpected fRtsControl value: %" PRId32
"\n",
714 if (lpDCB->fAbortOnError)
716 handflow.ControlHandShake |= SERIAL_ERROR_ABORT;
721 handflow.XonLimit = lpDCB->XonLim;
722 handflow.XoffLimit = lpDCB->XoffLim;
724 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow,
sizeof(
SERIAL_HANDFLOW),
725 nullptr, 0, &bytesReturned,
nullptr))
727 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the handflow settings.");
733 if (tcgetattr(pComm->fd, &upcomingTermios) <
736 SetLastError(ERROR_IO_DEVICE);
742 upcomingTermios.c_lflag &= (tcflag_t)~ICANON;
746 upcomingTermios.c_lflag |= ICANON;
747 CommLog_Print(WLOG_WARN,
"Unexpected nonbinary mode, consider to unset the ICANON flag.");
752 upcomingTermios.c_iflag |= INPCK;
756 upcomingTermios.c_iflag &= (tcflag_t)~INPCK;
770 if (comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
772 SetLastError(ERROR_IO_DEVICE);
785 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
786 DWORD bytesReturned = 0;
788 if (!CommIsHandleValid(hFile))
793 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_TIMEOUTS,
nullptr, 0, lpCommTimeouts,
796 CommLog_Print(WLOG_WARN,
"GetCommTimeouts failure.");
809 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
810 DWORD bytesReturned = 0;
812 if (!CommIsHandleValid(hFile))
817 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_TIMEOUTS, lpCommTimeouts,
sizeof(
COMMTIMEOUTS),
818 nullptr, 0, &bytesReturned,
nullptr))
820 CommLog_Print(WLOG_WARN,
"SetCommTimeouts failure.");
827BOOL GetDefaultCommConfigA(WINPR_ATTR_UNUSED LPCSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
828 WINPR_ATTR_UNUSED LPDWORD lpdwSize)
830 if (!CommInitialized())
834 CommLog_Print(WLOG_ERROR,
"Not implemented");
835 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
839BOOL GetDefaultCommConfigW(WINPR_ATTR_UNUSED LPCWSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
840 WINPR_ATTR_UNUSED LPDWORD lpdwSize)
842 if (!CommInitialized())
846 CommLog_Print(WLOG_ERROR,
"Not implemented");
847 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
851BOOL SetDefaultCommConfigA(WINPR_ATTR_UNUSED LPCSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
852 WINPR_ATTR_UNUSED DWORD dwSize)
854 if (!CommInitialized())
858 CommLog_Print(WLOG_ERROR,
"Not implemented");
859 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
863BOOL SetDefaultCommConfigW(WINPR_ATTR_UNUSED LPCWSTR lpszName, WINPR_ATTR_UNUSED
LPCOMMCONFIG lpCC,
864 WINPR_ATTR_UNUSED DWORD dwSize)
866 if (!CommInitialized())
870 CommLog_Print(WLOG_ERROR,
"Not implemented");
871 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
875BOOL SetCommBreak(HANDLE hFile)
877 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
879 if (!CommInitialized())
887 CommLog_Print(WLOG_ERROR,
"Not implemented");
888 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
892BOOL ClearCommBreak(HANDLE hFile)
894 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
896 if (!CommInitialized())
904 CommLog_Print(WLOG_ERROR,
"Not implemented");
905 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
909BOOL ClearCommError(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpErrors,
912 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
914 if (!CommInitialized())
922 CommLog_Print(WLOG_ERROR,
"Not implemented");
923 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
927BOOL PurgeComm(HANDLE hFile, DWORD dwFlags)
929 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
930 DWORD bytesReturned = 0;
932 if (!CommIsHandleValid(hFile))
935 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_PURGE, &dwFlags,
sizeof(DWORD),
nullptr, 0,
936 &bytesReturned,
nullptr))
938 CommLog_Print(WLOG_WARN,
"PurgeComm failure.");
945BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue)
947 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
949 DWORD bytesReturned = 0;
951 if (!CommIsHandleValid(hFile))
954 queueSize.InSize = dwInQueue;
955 queueSize.OutSize = dwOutQueue;
957 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_QUEUE_SIZE, &queueSize,
960 CommLog_Print(WLOG_WARN,
"SetCommTimeouts failure.");
967BOOL EscapeCommFunction(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwFunc)
969 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
971 if (!CommInitialized())
979 CommLog_Print(WLOG_ERROR,
"Not implemented");
980 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
984BOOL TransmitCommChar(HANDLE hFile, WINPR_ATTR_UNUSED
char cChar)
986 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
988 if (!CommInitialized())
996 CommLog_Print(WLOG_ERROR,
"Not implemented");
997 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1001BOOL WaitCommEvent(HANDLE hFile, WINPR_ATTR_UNUSED PDWORD lpEvtMask,
1004 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
1006 if (!CommInitialized())
1014 CommLog_Print(WLOG_ERROR,
"Not implemented");
1015 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1028BOOL DefineCommDevice( LPCTSTR lpDeviceName, LPCTSTR lpTargetPath)
1030 LPTSTR storedDeviceName =
nullptr;
1031 LPTSTR storedTargetPath =
nullptr;
1033 if (!CommInitialized())
1036 EnterCriticalSection(&sCommDevicesLock);
1038 if (sCommDevices ==
nullptr)
1040 SetLastError(ERROR_DLL_INIT_FAILED);
1044 storedDeviceName = _tcsdup(lpDeviceName);
1046 if (storedDeviceName ==
nullptr)
1048 SetLastError(ERROR_OUTOFMEMORY);
1052 storedTargetPath = _tcsdup(lpTargetPath);
1054 if (storedTargetPath ==
nullptr)
1056 SetLastError(ERROR_OUTOFMEMORY);
1062 for (; i < COMM_DEVICE_MAX; i++)
1064 if (sCommDevices[i] !=
nullptr)
1066 if (_tcscmp(sCommDevices[i]->name, storedDeviceName) == 0)
1069 free(sCommDevices[i]->name);
1070 free(sCommDevices[i]->path);
1071 sCommDevices[i]->name = storedDeviceName;
1072 sCommDevices[i]->path = storedTargetPath;
1079 sCommDevices[i] = (COMM_DEVICE*)calloc(1,
sizeof(COMM_DEVICE));
1081 if (sCommDevices[i] ==
nullptr)
1083 SetLastError(ERROR_OUTOFMEMORY);
1087 sCommDevices[i]->name = storedDeviceName;
1088 sCommDevices[i]->path = storedTargetPath;
1093 if (i == COMM_DEVICE_MAX)
1095 SetLastError(ERROR_OUTOFMEMORY);
1100 LeaveCriticalSection(&sCommDevicesLock);
1103 free(storedDeviceName);
1104 free(storedTargetPath);
1105 LeaveCriticalSection(&sCommDevicesLock);
1125DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax)
1127 LPTSTR storedTargetPath =
nullptr;
1128 SetLastError(ERROR_SUCCESS);
1130 if (!CommInitialized())
1133 if (sCommDevices ==
nullptr)
1135 SetLastError(ERROR_DLL_INIT_FAILED);
1139 if (lpDeviceName ==
nullptr || lpTargetPath ==
nullptr)
1141 SetLastError(ERROR_NOT_SUPPORTED);
1145 EnterCriticalSection(&sCommDevicesLock);
1146 storedTargetPath =
nullptr;
1148 for (
int i = 0; i < COMM_DEVICE_MAX; i++)
1150 if (sCommDevices[i] !=
nullptr)
1152 if (_tcscmp(sCommDevices[i]->name, lpDeviceName) == 0)
1154 storedTargetPath = sCommDevices[i]->path;
1164 LeaveCriticalSection(&sCommDevicesLock);
1166 if (storedTargetPath ==
nullptr)
1168 SetLastError(ERROR_INVALID_DATA);
1172 const size_t size = _tcsnlen(storedTargetPath, ucchMax);
1173 if (size + 2 > ucchMax)
1175 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1179 _tcsncpy(lpTargetPath, storedTargetPath, size + 1);
1180 lpTargetPath[size + 2] =
'\0';
1181 return (DWORD)size + 2UL;
1187BOOL IsCommDevice(LPCTSTR lpDeviceName)
1189 TCHAR lpTargetPath[MAX_PATH];
1191 if (!CommInitialized())
1194 if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0)
1205void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID driverId)
1209 WINPR_COMM* pComm =
nullptr;
1211 if (!CommInitialized())
1214 if (!winpr_Handle_GetInfo(hComm, &Type, &Object))
1216 CommLog_Print(WLOG_WARN,
"_comm_setServerSerialDriver failure");
1220 pComm = (WINPR_COMM*)Object;
1221 pComm->serverSerialDriverId = driverId;
1224static HANDLE_OPS ops = { CommIsHandled, CommCloseHandle, CommGetFd,
nullptr,
1225 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1226 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1227 nullptr,
nullptr,
nullptr,
nullptr,
nullptr };
1254HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode,
1255 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1256 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1258 CHAR devicePath[MAX_PATH] = WINPR_C_ARRAY_INIT;
1259 struct stat deviceStat = WINPR_C_ARRAY_INIT;
1260 WINPR_COMM* pComm =
nullptr;
1261 struct termios upcomingTermios = WINPR_C_ARRAY_INIT;
1263 if (!CommInitialized())
1264 return INVALID_HANDLE_VALUE;
1266 if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE))
1268 CommLog_Print(WLOG_WARN,
"unexpected access to the device: 0x%08" PRIX32
"",
1272 if (dwShareMode != 0)
1274 SetLastError(ERROR_SHARING_VIOLATION);
1275 return INVALID_HANDLE_VALUE;
1281 if (lpSecurityAttributes !=
nullptr)
1283 CommLog_Print(WLOG_WARN,
"unexpected security attributes, nLength=%" PRIu32
"",
1284 lpSecurityAttributes->nLength);
1287 if (dwCreationDisposition != OPEN_EXISTING)
1289 SetLastError(ERROR_FILE_NOT_FOUND);
1290 return INVALID_HANDLE_VALUE;
1293 if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0)
1296 return INVALID_HANDLE_VALUE;
1299 if (stat(devicePath, &deviceStat) < 0)
1301 CommLog_Print(WLOG_WARN,
"device not found %s", devicePath);
1302 SetLastError(ERROR_FILE_NOT_FOUND);
1303 return INVALID_HANDLE_VALUE;
1306 if (!S_ISCHR(deviceStat.st_mode))
1308 CommLog_Print(WLOG_WARN,
"bad device %s", devicePath);
1309 SetLastError(ERROR_BAD_DEVICE);
1310 return INVALID_HANDLE_VALUE;
1313 if (dwFlagsAndAttributes != 0)
1315 CommLog_Print(WLOG_WARN,
"unexpected flags and attributes: 0x%08" PRIX32
"",
1316 dwFlagsAndAttributes);
1319 if (hTemplateFile !=
nullptr)
1321 SetLastError(ERROR_NOT_SUPPORTED);
1322 return INVALID_HANDLE_VALUE;
1325 pComm = (WINPR_COMM*)calloc(1,
sizeof(WINPR_COMM));
1327 if (pComm ==
nullptr)
1329 SetLastError(ERROR_OUTOFMEMORY);
1330 return INVALID_HANDLE_VALUE;
1333 WINPR_HANDLE_SET_TYPE_AND_MODE(pComm, HANDLE_TYPE_COMM, WINPR_FD_READ);
1334 pComm->common.ops = &ops;
1336 pComm->fd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
1340 CommLog_Print(WLOG_WARN,
"failed to open device %s", devicePath);
1341 SetLastError(ERROR_BAD_DEVICE);
1345 pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK);
1347 if (pComm->fd_read < 0)
1349 CommLog_Print(WLOG_WARN,
"failed to open fd_read, device: %s", devicePath);
1350 SetLastError(ERROR_BAD_DEVICE);
1354#if defined(WINPR_HAVE_SYS_EVENTFD_H)
1355 pComm->fd_read_event = eventfd(
1359 if (pComm->fd_read_event < 0)
1361 CommLog_Print(WLOG_WARN,
"failed to open fd_read_event, device: %s", devicePath);
1362 SetLastError(ERROR_BAD_DEVICE);
1366 InitializeCriticalSection(&pComm->ReadLock);
1367 pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK);
1369 if (pComm->fd_write < 0)
1371 CommLog_Print(WLOG_WARN,
"failed to open fd_write, device: %s", devicePath);
1372 SetLastError(ERROR_BAD_DEVICE);
1376#if defined(WINPR_HAVE_SYS_EVENTFD_H)
1377 pComm->fd_write_event = eventfd(
1381 if (pComm->fd_write_event < 0)
1383 CommLog_Print(WLOG_WARN,
"failed to open fd_write_event, device: %s", devicePath);
1384 SetLastError(ERROR_BAD_DEVICE);
1388 InitializeCriticalSection(&pComm->WriteLock);
1390 pComm->serverSerialDriverId = SerialDriverUnknown;
1391 InitializeCriticalSection(&pComm->EventsLock);
1393 (void)CommUpdateIOCount(pComm, TRUE);
1398 ZeroMemory(&upcomingTermios,
sizeof(
struct termios));
1400 if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
1402 SetLastError(ERROR_IO_DEVICE);
1406 upcomingTermios.c_iflag &=
1407 (tcflag_t) ~( BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL );
1408 upcomingTermios.c_oflag = 0;
1409 upcomingTermios.c_lflag = 0;
1418 upcomingTermios.c_cflag |= CLOCAL | CREAD;
1420 if (comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
1422 SetLastError(ERROR_IO_DEVICE);
1426 return (HANDLE)pComm;
1428 WINPR_PRAGMA_DIAG_PUSH
1429 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC(
void) CloseHandle(pComm);
1430 WINPR_PRAGMA_DIAG_POP
1431 return INVALID_HANDLE_VALUE;
1434BOOL CommIsHandled(HANDLE handle)
1436 if (!CommInitialized())
1439 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_COMM, TRUE);
1442BOOL CommIsHandleValid(HANDLE handle)
1444 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1445 if (!CommIsHandled(handle))
1449 SetLastError(ERROR_INVALID_HANDLE);
1455BOOL CommCloseHandle(HANDLE handle)
1457 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1459 if (!CommIsHandled(handle))
1462 DeleteCriticalSection(&pComm->ReadLock);
1463 DeleteCriticalSection(&pComm->WriteLock);
1464 DeleteCriticalSection(&pComm->EventsLock);
1469 if (pComm->fd_write > 0)
1470 close(pComm->fd_write);
1472 if (pComm->fd_write_event > 0)
1473 close(pComm->fd_write_event);
1475 if (pComm->fd_read > 0)
1476 close(pComm->fd_read);
1478 if (pComm->fd_read_event > 0)
1479 close(pComm->fd_read_event);
1485#if defined(WINPR_HAVE_SYS_EVENTFD_H)
1486#ifndef WITH_EVENTFD_READ_WRITE
1487int eventfd_read(
int fd, eventfd_t* value)
1489 return (read(fd, value,
sizeof(*value)) ==
sizeof(*value)) ? 0 : -1;
1492int eventfd_write(
int fd, eventfd_t value)
1494 return (write(fd, &value,
sizeof(value)) ==
sizeof(value)) ? 0 : -1;
1499static const char* CommIoCtlToStr(
unsigned long int io)
1503#if defined(WINPR_HAVE_SERIAL_SUPPORT)
1548#if defined(TIOCEXCL)
1552#if defined(TIOCNXCL)
1556#if defined(TIOCSCTTY)
1560#if defined(TIOCGPGRP)
1564#if defined(TIOCSPGRP)
1568#if defined(TIOCOUTQ)
1576#if defined(TIOCGWINSZ)
1578 return "TIOCGWINSZ";
1580#if defined(TIOCSWINSZ)
1582 return "TIOCSWINSZ";
1584#if defined(TIOCMGET)
1588#if defined(TIOCMBIS)
1592#if defined(TIOCMBIC)
1596#if defined(TIOCMSET)
1600#if defined(TIOCGSOFTCAR)
1602 return "TIOCGSOFTCAR";
1604#if defined(TIOCSSOFTCAR)
1606 return "TIOCSSOFTCAR";
1608#if defined(FIONREAD)
1610 return "FIONREAD/TIOCINQ";
1612#if defined(TIOCLINUX)
1616#if defined(TIOCCONS)
1620#if defined(TIOCGSERIAL)
1622 return "TIOCGSERIAL";
1624#if defined(TIOCSSERIAL)
1626 return "TIOCSSERIAL";
1636#if defined(TIOCNOTTY)
1640#if defined(TIOCSETD)
1644#if defined(TIOCGETD)
1652#if defined(TIOCSBRK)
1656#if defined(TIOCCBRK)
1660#if defined(TIOCGSID)
1664#if defined(TIOCGRS485)
1666 return "TIOCGRS485";
1668#if defined(TIOCSRS485)
1670 return "TIOCSRS485";
1672#if defined(TIOCSPTLCK)
1674 return "TIOCSPTLCK";
1696#if defined(TIOCVHANGUP)
1698 return "TIOCVHANGUP";
1700#if defined(TIOCGPTPEER)
1702 return "TIOCGPTPEER";
1704#if defined(FIONCLEX)
1712#if defined(FIOASYNC)
1716#if defined(TIOCSERCONFIG)
1718 return "TIOCSERCONFIG";
1720#if defined(TIOCSERGWILD)
1722 return "TIOCSERGWILD";
1724#if defined(TIOCSERSWILD)
1726 return "TIOCSERSWILD";
1728#if defined(TIOCGLCKTRMIOS)
1729 case TIOCGLCKTRMIOS:
1730 return "TIOCGLCKTRMIOS";
1732#if defined(TIOCSLCKTRMIOS)
1733 case TIOCSLCKTRMIOS:
1734 return "TIOCSLCKTRMIOS";
1736#if defined(TIOCSERGSTRUCT)
1737 case TIOCSERGSTRUCT:
1738 return "TIOCSERGSTRUCT";
1740#if defined(TIOCSERGETLSR)
1742 return "TIOCSERGETLSR";
1744#if defined(TIOCSERGETMULTI)
1745 case TIOCSERGETMULTI:
1746 return "TIOCSERGETMULTI";
1748#if defined(TIOCSERSETMULTI)
1749 case TIOCSERSETMULTI:
1750 return "TIOCSERSETMULTI";
1752#if defined(TIOCMIWAIT)
1754 return "TIOCMIWAIT";
1756#if defined(TIOCGICOUNT)
1758 return "TIOCGICOUNT";
1760#if defined(FIOQSIZE)
1764#if defined(TIOCPKT_DATA)
1766 return "TIOCPKT_DATA";
1768#if defined(TIOCPKT_FLUSHWRITE)
1769 case TIOCPKT_FLUSHWRITE:
1770 return "TIOCPKT_FLUSHWRITE";
1772#if defined(TIOCPKT_STOP)
1774 return "TIOCPKT_STOP";
1776#if defined(TIOCPKT_START)
1778 return "TIOCPKT_START";
1780#if defined(TIOCPKT_NOSTOP)
1781 case TIOCPKT_NOSTOP:
1782 return "TIOCPKT_NOSTOP";
1784#if defined(TIOCPKT_DOSTOP)
1785 case TIOCPKT_DOSTOP:
1786 return "TIOCPKT_DOSTOP";
1788#if defined(TIOCPKT_IOCTL)
1790 return "TIOCPKT_IOCTL";
1798static BOOL CommStatusErrorEx(WINPR_COMM* pComm,
unsigned long int ctl,
const char* file,
1799 const char* fkt,
size_t line)
1801 WINPR_ASSERT(pComm);
1802 BOOL rc = (pComm->permissive);
1803 const DWORD level = rc ? WLOG_DEBUG : WLOG_WARN;
1804 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1805 const char* str = CommIoCtlToStr(ctl);
1807 if (CommInitialized())
1809 if (WLog_IsLevelActive(sLog, level))
1811 WLog_PrintTextMessage(sLog, level, line, file, fkt,
1812 "%s [0x%08lx] ioctl failed, errno=[%d] %s.", str, ctl, errno,
1813 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
1818 SetLastError(ERROR_IO_DEVICE);
1823BOOL CommIoCtl_int(WINPR_COMM* pComm,
unsigned long int ctl,
void* data,
const char* file,
1824 const char* fkt,
size_t line)
1826 if (ioctl(pComm->fd, ctl, data) < 0)
1828 if (!CommStatusErrorEx(pComm, ctl, file, fkt, line))
1834BOOL CommUpdateIOCount(WINPR_ATTR_UNUSED HANDLE handle, WINPR_ATTR_UNUSED BOOL checkSupportStatus)
1836 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1837 WINPR_ASSERT(pComm);
1839#if defined(WINPR_HAVE_COMM_COUNTERS)
1840 ZeroMemory(&(pComm->counters),
sizeof(
struct serial_icounter_struct));
1841 if (pComm->TIOCGICOUNTSupported || checkSupportStatus)
1843 const int rc = ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters));
1844 if (checkSupportStatus)
1845 pComm->TIOCGICOUNTSupported = rc >= 0;
1848 if (!CommStatusErrorEx(pComm, TIOCGICOUNT, __FILE__, __func__, __LINE__))
1856static const char* CommSerialEvFlagString(ULONG flag)
1860 case SERIAL_EV_RXCHAR:
1861 return "SERIAL_EV_RXCHAR";
1862 case SERIAL_EV_RXFLAG:
1863 return "SERIAL_EV_RXFLAG";
1864 case SERIAL_EV_TXEMPTY:
1865 return "SERIAL_EV_TXEMPTY";
1867 return "SERIAL_EV_CTS ";
1869 return "SERIAL_EV_DSR ";
1870 case SERIAL_EV_RLSD:
1871 return "SERIAL_EV_RLSD";
1872 case SERIAL_EV_BREAK:
1873 return "SERIAL_EV_BREAK";
1875 return "SERIAL_EV_ERR ";
1876 case SERIAL_EV_RING:
1877 return "SERIAL_EV_RING";
1878 case SERIAL_EV_PERR:
1879 return "SERIAL_EV_PERR";
1880 case SERIAL_EV_RX80FULL:
1881 return "SERIAL_EV_RX80FULL";
1882 case SERIAL_EV_EVENT1:
1883 return "SERIAL_EV_EVENT1";
1884 case SERIAL_EV_EVENT2:
1885 return "SERIAL_EV_EVENT2";
1886 case SERIAL_EV_WINPR_WAITING:
1887 return "SERIAL_EV_WINPR_WAITING";
1888 case SERIAL_EV_WINPR_STOP:
1889 return "SERIAL_EV_WINPR_STOP";
1891 return "SERIAL_EV_UNKNOWN";
1895const char* CommSerialEvString(ULONG status,
char* buffer,
size_t size)
1897 const ULONG flags[] = { SERIAL_EV_RXCHAR, SERIAL_EV_RXFLAG, SERIAL_EV_TXEMPTY,
1898 SERIAL_EV_CTS, SERIAL_EV_DSR, SERIAL_EV_RLSD,
1899 SERIAL_EV_BREAK, SERIAL_EV_ERR, SERIAL_EV_RING,
1900 SERIAL_EV_PERR, SERIAL_EV_RX80FULL, SERIAL_EV_EVENT1,
1901 SERIAL_EV_EVENT2, SERIAL_EV_WINPR_WAITING, SERIAL_EV_WINPR_STOP };
1903 winpr_str_append(
"{", buffer, size,
"");
1905 const char* sep =
"";
1906 for (
size_t x = 0; x < ARRAYSIZE(flags); x++)
1908 const ULONG flag = flags[x];
1911 winpr_str_append(CommSerialEvFlagString(flag), buffer, size, sep);
1916 char number[32] = WINPR_C_ARRAY_INIT;
1917 (void)_snprintf(number,
sizeof(number),
"}[0x%08" PRIx32
"]", status);
1918 winpr_str_append(number, buffer, size,
"");