23 #include <winpr/config.h>
25 #include <winpr/assert.h>
30 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
31 #include <sys/eventfd.h>
33 #include <sys/ioctl.h>
35 #include <sys/types.h>
39 #include <winpr/crt.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")
57 static wLog* sLog = NULL;
65 typedef struct comm_device COMM_DEVICE;
69 #define COMM_DEVICE_MAX 128
70 static COMM_DEVICE** sCommDevices = NULL;
73 static 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" }
129 const char* _comm_serial_ioctl_name(ULONG number)
131 for (
size_t x = 0; x < ARRAYSIZE(S_SERIAL_IOCTL_NAMES); x++)
134 if (cur->number == number)
138 return "(unknown ioctl name)";
141 static int CommGetFd(HANDLE handle)
143 WINPR_COMM* comm = (WINPR_COMM*)handle;
145 if (!CommIsHandled(handle))
153 #if defined(WINPR_HAVE_SERIAL_SUPPORT)
154 static const HANDLE_CREATOR sCommHandleCreator = { .IsHandled = IsCommDevice,
155 .CreateFileA = CommCreateFileA };
156 return &sCommHandleCreator;
162 static void CommInit(
void)
165 WINPR_ASSERT(sLog == NULL);
166 WINPR_ASSERT(sCommDevices == NULL);
167 sCommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX + 1,
sizeof(COMM_DEVICE*));
172 if (!InitializeCriticalSectionEx(&sCommDevicesLock, 0, 0))
179 sLog = WLog_Get(TAG);
180 WINPR_ASSERT(sLog != NULL);
187 static BOOL CommInitialized(
void)
189 if (pthread_once(&sCommInitialized, CommInit) != 0)
191 SetLastError(ERROR_DLL_INIT_FAILED);
198 void CommLog_Print(DWORD level, ...)
200 if (!CommInitialized())
205 WLog_PrintVA(sLog, level, ap);
209 BOOL BuildCommDCBA(LPCSTR lpDef,
LPDCB lpDCB)
211 if (!CommInitialized())
215 CommLog_Print(WLOG_ERROR,
"Not implemented");
216 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
220 BOOL BuildCommDCBW(LPCWSTR lpDef,
LPDCB lpDCB)
222 if (!CommInitialized())
226 CommLog_Print(WLOG_ERROR,
"Not implemented");
227 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
233 if (!CommInitialized())
237 CommLog_Print(WLOG_ERROR,
"Not implemented");
238 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
244 if (!CommInitialized())
248 CommLog_Print(WLOG_ERROR,
"Not implemented");
249 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
253 BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd,
LPCOMMCONFIG lpCC)
255 if (!CommInitialized())
259 CommLog_Print(WLOG_ERROR,
"Not implemented");
260 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
264 BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd,
LPCOMMCONFIG lpCC)
266 if (!CommInitialized())
270 CommLog_Print(WLOG_ERROR,
"Not implemented");
271 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
275 BOOL GetCommConfig(HANDLE hCommDev,
LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
277 WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
279 if (!CommInitialized())
287 CommLog_Print(WLOG_ERROR,
"Not implemented");
288 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
292 BOOL SetCommConfig(HANDLE hCommDev,
LPCOMMCONFIG lpCC, DWORD dwSize)
294 WINPR_COMM* pComm = (WINPR_COMM*)hCommDev;
296 if (!CommInitialized())
304 CommLog_Print(WLOG_ERROR,
"Not implemented");
305 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
309 BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask)
311 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
313 if (!CommInitialized())
321 CommLog_Print(WLOG_ERROR,
"Not implemented");
322 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
326 BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask)
328 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
330 if (!CommInitialized())
338 CommLog_Print(WLOG_ERROR,
"Not implemented");
339 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
343 BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat)
345 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
347 if (!CommInitialized())
355 CommLog_Print(WLOG_ERROR,
"Not implemented");
356 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
365 BOOL GetCommProperties(HANDLE hFile,
LPCOMMPROP lpCommProp)
367 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
368 DWORD bytesReturned = 0;
370 if (!CommIsHandleValid(hFile))
373 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, lpCommProp,
374 sizeof(
COMMPROP), &bytesReturned, NULL))
376 CommLog_Print(WLOG_WARN,
"GetCommProperties failure.");
392 BOOL GetCommState(HANDLE hFile,
LPDCB lpDCB)
394 DCB* lpLocalDcb = NULL;
395 struct termios currentState;
396 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
397 DWORD bytesReturned = 0;
399 if (!CommIsHandleValid(hFile))
404 SetLastError(ERROR_INVALID_DATA);
408 if (lpDCB->DCBlength <
sizeof(
DCB))
410 SetLastError(ERROR_INVALID_DATA);
414 if (tcgetattr(pComm->fd, ¤tState) < 0)
416 SetLastError(ERROR_IO_DEVICE);
420 lpLocalDcb = (
DCB*)calloc(1, lpDCB->DCBlength);
422 if (lpLocalDcb == NULL)
424 SetLastError(ERROR_OUTOFMEMORY);
429 lpLocalDcb->DCBlength = lpDCB->DCBlength;
432 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &baudRate,
435 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the baud rate.");
439 lpLocalDcb->BaudRate = baudRate.BaudRate;
440 lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0;
442 if (!lpLocalDcb->fBinary)
444 CommLog_Print(WLOG_WARN,
"Unexpected nonbinary mode, consider to unset the ICANON flag.");
447 lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0;
450 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow,
453 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the handflow settings.");
457 lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0;
458 lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0;
460 if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
462 lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
464 else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL)
466 lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE;
470 lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE;
473 lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0;
474 lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0;
475 lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0;
476 lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0;
477 lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0;
478 lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0;
480 if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
482 lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
484 else if (handflow.FlowReplace & SERIAL_RTS_CONTROL)
486 lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE;
490 lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE;
495 lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0;
497 lpLocalDcb->wReserved = 0;
498 lpLocalDcb->XonLim = handflow.XonLimit;
499 lpLocalDcb->XoffLim = handflow.XoffLimit;
502 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl,
505 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the control settings.");
509 lpLocalDcb->ByteSize = lineControl.WordLength;
510 lpLocalDcb->Parity = lineControl.Parity;
511 lpLocalDcb->StopBits = lineControl.StopBits;
514 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars,
517 CommLog_Print(WLOG_WARN,
"GetCommState failure: could not get the serial chars.");
521 lpLocalDcb->XonChar = serialChars.XonChar;
522 lpLocalDcb->XoffChar = serialChars.XoffChar;
523 lpLocalDcb->ErrorChar = serialChars.ErrorChar;
524 lpLocalDcb->EofChar = serialChars.EofChar;
525 lpLocalDcb->EvtChar = serialChars.EventChar;
526 memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength);
545 BOOL SetCommState(HANDLE hFile,
LPDCB lpDCB)
547 struct termios upcomingTermios = { 0 };
548 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
549 DWORD bytesReturned = 0;
553 if (!CommIsHandleValid(hFile))
558 SetLastError(ERROR_INVALID_DATA);
566 baudRate.BaudRate = lpDCB->BaudRate;
568 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate,
sizeof(
SERIAL_BAUD_RATE),
569 NULL, 0, &bytesReturned, NULL))
571 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the baud rate.");
577 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars,
581 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not get the initial serial chars.");
585 serialChars.XonChar = lpDCB->XonChar;
586 serialChars.XoffChar = lpDCB->XoffChar;
587 serialChars.ErrorChar = lpDCB->ErrorChar;
588 serialChars.EofChar = lpDCB->EofChar;
589 serialChars.EventChar = lpDCB->EvtChar;
591 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars,
sizeof(
SERIAL_CHARS),
592 NULL, 0, &bytesReturned, NULL))
594 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the serial chars.");
599 lineControl.StopBits = lpDCB->StopBits;
600 lineControl.Parity = lpDCB->Parity;
601 lineControl.WordLength = lpDCB->ByteSize;
603 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_LINE_CONTROL, &lineControl,
606 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the control settings.");
612 if (lpDCB->fOutxCtsFlow)
614 handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
617 if (lpDCB->fOutxDsrFlow)
619 handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
622 switch (lpDCB->fDtrControl)
624 case SERIAL_DTR_HANDSHAKE:
625 handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE;
628 case SERIAL_DTR_CONTROL:
629 handflow.ControlHandShake |= DTR_CONTROL_ENABLE;
632 case DTR_CONTROL_DISABLE:
637 CommLog_Print(WLOG_WARN,
"Unexpected fDtrControl value: %" PRIu32
"\n",
642 if (lpDCB->fDsrSensitivity)
644 handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
647 if (lpDCB->fTXContinueOnXoff)
649 handflow.FlowReplace |= SERIAL_XOFF_CONTINUE;
654 handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
659 handflow.FlowReplace |= SERIAL_AUTO_RECEIVE;
662 if (lpDCB->fErrorChar)
664 handflow.FlowReplace |= SERIAL_ERROR_CHAR;
669 handflow.FlowReplace |= SERIAL_NULL_STRIPPING;
672 switch (lpDCB->fRtsControl)
674 case RTS_CONTROL_TOGGLE:
675 CommLog_Print(WLOG_WARN,
"Unsupported RTS_CONTROL_TOGGLE feature");
679 case RTS_CONTROL_HANDSHAKE:
680 handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
683 case RTS_CONTROL_ENABLE:
684 handflow.FlowReplace |= SERIAL_RTS_CONTROL;
687 case RTS_CONTROL_DISABLE:
692 CommLog_Print(WLOG_WARN,
"Unexpected fRtsControl value: %" PRIu32
"\n",
697 if (lpDCB->fAbortOnError)
699 handflow.ControlHandShake |= SERIAL_ERROR_ABORT;
704 handflow.XonLimit = lpDCB->XonLim;
705 handflow.XoffLimit = lpDCB->XoffLim;
707 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow,
sizeof(
SERIAL_HANDFLOW),
708 NULL, 0, &bytesReturned, NULL))
710 CommLog_Print(WLOG_WARN,
"SetCommState failure: could not set the handflow settings.");
716 if (tcgetattr(pComm->fd, &upcomingTermios) <
719 SetLastError(ERROR_IO_DEVICE);
725 upcomingTermios.c_lflag &= ~ICANON;
729 upcomingTermios.c_lflag |= ICANON;
730 CommLog_Print(WLOG_WARN,
"Unexpected nonbinary mode, consider to unset the ICANON flag.");
735 upcomingTermios.c_iflag |= INPCK;
739 upcomingTermios.c_iflag &= ~INPCK;
753 if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
755 SetLastError(ERROR_IO_DEVICE);
768 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
769 DWORD bytesReturned = 0;
771 if (!CommIsHandleValid(hFile))
776 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, lpCommTimeouts,
779 CommLog_Print(WLOG_WARN,
"GetCommTimeouts failure.");
792 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
793 DWORD bytesReturned = 0;
795 if (!CommIsHandleValid(hFile))
800 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_TIMEOUTS, lpCommTimeouts,
sizeof(
COMMTIMEOUTS),
801 NULL, 0, &bytesReturned, NULL))
803 CommLog_Print(WLOG_WARN,
"SetCommTimeouts failure.");
810 BOOL GetDefaultCommConfigA(LPCSTR lpszName,
LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
812 if (!CommInitialized())
816 CommLog_Print(WLOG_ERROR,
"Not implemented");
817 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
821 BOOL GetDefaultCommConfigW(LPCWSTR lpszName,
LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
823 if (!CommInitialized())
827 CommLog_Print(WLOG_ERROR,
"Not implemented");
828 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
832 BOOL SetDefaultCommConfigA(LPCSTR lpszName,
LPCOMMCONFIG lpCC, DWORD dwSize)
834 if (!CommInitialized())
838 CommLog_Print(WLOG_ERROR,
"Not implemented");
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
843 BOOL SetDefaultCommConfigW(LPCWSTR lpszName,
LPCOMMCONFIG lpCC, DWORD dwSize)
845 if (!CommInitialized())
849 CommLog_Print(WLOG_ERROR,
"Not implemented");
850 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
854 BOOL SetCommBreak(HANDLE hFile)
856 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
858 if (!CommInitialized())
866 CommLog_Print(WLOG_ERROR,
"Not implemented");
867 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
871 BOOL ClearCommBreak(HANDLE hFile)
873 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
875 if (!CommInitialized())
883 CommLog_Print(WLOG_ERROR,
"Not implemented");
884 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
888 BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors,
LPCOMSTAT lpStat)
890 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
892 if (!CommInitialized())
900 CommLog_Print(WLOG_ERROR,
"Not implemented");
901 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
905 BOOL PurgeComm(HANDLE hFile, DWORD dwFlags)
907 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
908 DWORD bytesReturned = 0;
910 if (!CommIsHandleValid(hFile))
913 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_PURGE, &dwFlags,
sizeof(DWORD), NULL, 0,
914 &bytesReturned, NULL))
916 CommLog_Print(WLOG_WARN,
"PurgeComm failure.");
923 BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue)
925 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
927 DWORD bytesReturned = 0;
929 if (!CommIsHandleValid(hFile))
932 queueSize.InSize = dwInQueue;
933 queueSize.OutSize = dwOutQueue;
935 if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_QUEUE_SIZE, &queueSize,
938 CommLog_Print(WLOG_WARN,
"SetCommTimeouts failure.");
945 BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc)
947 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
949 if (!CommInitialized())
957 CommLog_Print(WLOG_ERROR,
"Not implemented");
958 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
962 BOOL TransmitCommChar(HANDLE hFile,
char cChar)
964 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
966 if (!CommInitialized())
974 CommLog_Print(WLOG_ERROR,
"Not implemented");
975 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
979 BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask,
LPOVERLAPPED lpOverlapped)
981 WINPR_COMM* pComm = (WINPR_COMM*)hFile;
983 if (!CommInitialized())
991 CommLog_Print(WLOG_ERROR,
"Not implemented");
992 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1005 BOOL DefineCommDevice( LPCTSTR lpDeviceName, LPCTSTR lpTargetPath)
1007 LPTSTR storedDeviceName = NULL;
1008 LPTSTR storedTargetPath = NULL;
1010 if (!CommInitialized())
1013 EnterCriticalSection(&sCommDevicesLock);
1015 if (sCommDevices == NULL)
1017 SetLastError(ERROR_DLL_INIT_FAILED);
1021 storedDeviceName = _tcsdup(lpDeviceName);
1023 if (storedDeviceName == NULL)
1025 SetLastError(ERROR_OUTOFMEMORY);
1029 storedTargetPath = _tcsdup(lpTargetPath);
1031 if (storedTargetPath == NULL)
1033 SetLastError(ERROR_OUTOFMEMORY);
1038 for (; i < COMM_DEVICE_MAX; i++)
1040 if (sCommDevices[i] != NULL)
1042 if (_tcscmp(sCommDevices[i]->name, storedDeviceName) == 0)
1045 free(sCommDevices[i]->name);
1046 free(sCommDevices[i]->path);
1047 sCommDevices[i]->name = storedDeviceName;
1048 sCommDevices[i]->path = storedTargetPath;
1055 sCommDevices[i] = (COMM_DEVICE*)calloc(1,
sizeof(COMM_DEVICE));
1057 if (sCommDevices[i] == NULL)
1059 SetLastError(ERROR_OUTOFMEMORY);
1063 sCommDevices[i]->name = storedDeviceName;
1064 sCommDevices[i]->path = storedTargetPath;
1069 if (i == COMM_DEVICE_MAX)
1071 SetLastError(ERROR_OUTOFMEMORY);
1075 LeaveCriticalSection(&sCommDevicesLock);
1078 free(storedDeviceName);
1079 free(storedTargetPath);
1080 LeaveCriticalSection(&sCommDevicesLock);
1100 DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax)
1102 LPTSTR storedTargetPath = NULL;
1103 SetLastError(ERROR_SUCCESS);
1105 if (!CommInitialized())
1108 if (sCommDevices == NULL)
1110 SetLastError(ERROR_DLL_INIT_FAILED);
1114 if (lpDeviceName == NULL || lpTargetPath == NULL)
1116 SetLastError(ERROR_NOT_SUPPORTED);
1120 EnterCriticalSection(&sCommDevicesLock);
1121 storedTargetPath = NULL;
1123 for (
int i = 0; i < COMM_DEVICE_MAX; i++)
1125 if (sCommDevices[i] != NULL)
1127 if (_tcscmp(sCommDevices[i]->name, lpDeviceName) == 0)
1129 storedTargetPath = sCommDevices[i]->path;
1139 LeaveCriticalSection(&sCommDevicesLock);
1141 if (storedTargetPath == NULL)
1143 SetLastError(ERROR_INVALID_DATA);
1147 const size_t size = _tcsnlen(storedTargetPath, ucchMax);
1148 if (size + 2 > ucchMax)
1150 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1154 _tcsncpy(lpTargetPath, storedTargetPath, size + 1);
1155 lpTargetPath[size + 2] =
'\0';
1156 return (DWORD)size + 2UL;
1162 BOOL IsCommDevice(LPCTSTR lpDeviceName)
1164 TCHAR lpTargetPath[MAX_PATH];
1166 if (!CommInitialized())
1169 if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0)
1180 void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID driverId)
1184 WINPR_COMM* pComm = NULL;
1186 if (!CommInitialized())
1189 if (!winpr_Handle_GetInfo(hComm, &Type, &Object))
1191 CommLog_Print(WLOG_WARN,
"_comm_setServerSerialDriver failure");
1195 pComm = (WINPR_COMM*)Object;
1196 pComm->serverSerialDriverId = driverId;
1199 static HANDLE_OPS ops = { CommIsHandled, CommCloseHandle,
1236 HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode,
1237 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1238 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1240 CHAR devicePath[MAX_PATH] = { 0 };
1241 struct stat deviceStat = { 0 };
1242 WINPR_COMM* pComm = NULL;
1243 struct termios upcomingTermios = { 0 };
1245 if (!CommInitialized())
1246 return INVALID_HANDLE_VALUE;
1248 if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE))
1250 CommLog_Print(WLOG_WARN,
"unexpected access to the device: 0x%08" PRIX32
"",
1254 if (dwShareMode != 0)
1256 SetLastError(ERROR_SHARING_VIOLATION);
1257 return INVALID_HANDLE_VALUE;
1263 if (lpSecurityAttributes != NULL)
1265 CommLog_Print(WLOG_WARN,
"unexpected security attributes, nLength=%" PRIu32
"",
1266 lpSecurityAttributes->nLength);
1269 if (dwCreationDisposition != OPEN_EXISTING)
1271 SetLastError(ERROR_FILE_NOT_FOUND);
1272 return INVALID_HANDLE_VALUE;
1275 if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0)
1278 return INVALID_HANDLE_VALUE;
1281 if (stat(devicePath, &deviceStat) < 0)
1283 CommLog_Print(WLOG_WARN,
"device not found %s", devicePath);
1284 SetLastError(ERROR_FILE_NOT_FOUND);
1285 return INVALID_HANDLE_VALUE;
1288 if (!S_ISCHR(deviceStat.st_mode))
1290 CommLog_Print(WLOG_WARN,
"bad device %s", devicePath);
1291 SetLastError(ERROR_BAD_DEVICE);
1292 return INVALID_HANDLE_VALUE;
1295 if (dwFlagsAndAttributes != 0)
1297 CommLog_Print(WLOG_WARN,
"unexpected flags and attributes: 0x%08" PRIX32
"",
1298 dwFlagsAndAttributes);
1301 if (hTemplateFile != NULL)
1303 SetLastError(ERROR_NOT_SUPPORTED);
1304 return INVALID_HANDLE_VALUE;
1307 pComm = (WINPR_COMM*)calloc(1,
sizeof(WINPR_COMM));
1311 SetLastError(ERROR_OUTOFMEMORY);
1312 return INVALID_HANDLE_VALUE;
1315 WINPR_HANDLE_SET_TYPE_AND_MODE(pComm, HANDLE_TYPE_COMM, WINPR_FD_READ);
1316 pComm->common.ops = &ops;
1318 pComm->fd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
1322 CommLog_Print(WLOG_WARN,
"failed to open device %s", devicePath);
1323 SetLastError(ERROR_BAD_DEVICE);
1327 pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK);
1329 if (pComm->fd_read < 0)
1331 CommLog_Print(WLOG_WARN,
"failed to open fd_read, device: %s", devicePath);
1332 SetLastError(ERROR_BAD_DEVICE);
1336 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
1337 pComm->fd_read_event = eventfd(
1341 if (pComm->fd_read_event < 0)
1343 CommLog_Print(WLOG_WARN,
"failed to open fd_read_event, device: %s", devicePath);
1344 SetLastError(ERROR_BAD_DEVICE);
1348 InitializeCriticalSection(&pComm->ReadLock);
1349 pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK);
1351 if (pComm->fd_write < 0)
1353 CommLog_Print(WLOG_WARN,
"failed to open fd_write, device: %s", devicePath);
1354 SetLastError(ERROR_BAD_DEVICE);
1358 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
1359 pComm->fd_write_event = eventfd(
1363 if (pComm->fd_write_event < 0)
1365 CommLog_Print(WLOG_WARN,
"failed to open fd_write_event, device: %s", devicePath);
1366 SetLastError(ERROR_BAD_DEVICE);
1370 InitializeCriticalSection(&pComm->WriteLock);
1372 pComm->serverSerialDriverId = SerialDriverUnknown;
1373 InitializeCriticalSection(&pComm->EventsLock);
1375 #if defined(WINPR_HAVE_COMM_COUNTERS)
1376 if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0)
1378 char ebuffer[256] = { 0 };
1379 CommLog_Print(WLOG_WARN,
"TIOCGICOUNT ioctl failed, errno=[%d] %s.", errno,
1380 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
1381 CommLog_Print(WLOG_WARN,
"could not read counters.");
1388 ZeroMemory(&(pComm->counters),
sizeof(
struct serial_icounter_struct));
1395 ZeroMemory(&upcomingTermios,
sizeof(
struct termios));
1397 if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
1399 SetLastError(ERROR_IO_DEVICE);
1403 upcomingTermios.c_iflag &=
1404 ~( 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;
1431 BOOL CommIsHandled(HANDLE handle)
1433 if (!CommInitialized())
1436 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_COMM, TRUE);
1439 BOOL CommIsHandleValid(HANDLE handle)
1441 WINPR_COMM* pComm = (WINPR_COMM*)handle;
1442 if (!CommIsHandled(handle))
1446 SetLastError(ERROR_INVALID_HANDLE);
1452 BOOL 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
1484 int eventfd_read(
int fd, eventfd_t* value)
1486 return (read(fd, value,
sizeof(*value)) ==
sizeof(*value)) ? 0 : -1;
1489 int eventfd_write(
int fd, eventfd_t value)
1491 return (write(fd, &value,
sizeof(value)) ==
sizeof(value)) ? 0 : -1;