23 #include <winpr/config.h>
25 #include <winpr/assert.h>
28 #include <winpr/wlog.h>
31 #include "comm_ioctl.h"
32 #include "comm_serial_sys.h"
33 #include "comm_sercx_sys.h"
34 #include "comm_sercx2_sys.h"
51 static BOOL s_CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
52 DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
55 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
58 if (!CommIsHandleValid(hDevice))
63 SetLastError(ERROR_NOT_SUPPORTED);
67 if (lpBytesReturned == NULL)
69 SetLastError(ERROR_INVALID_PARAMETER);
74 SetLastError(ERROR_SUCCESS);
78 CommLog_Print(WLOG_DEBUG,
"CommDeviceIoControl: IoControlCode: 0x%0.8x", dwIoControlCode);
84 switch (pComm->serverSerialDriverId)
86 case SerialDriverSerialSys:
87 pServerSerialDriver = SerialSys_s();
90 case SerialDriverSerCxSys:
91 pServerSerialDriver = SerCxSys_s();
94 case SerialDriverSerCx2Sys:
95 pServerSerialDriver = SerCx2Sys_s();
98 case SerialDriverUnknown:
100 CommLog_Print(WLOG_DEBUG,
"Unknown remote serial driver (%d), using SerCx2.sys",
101 pComm->serverSerialDriverId);
102 pServerSerialDriver = SerCx2Sys_s();
106 WINPR_ASSERT(pServerSerialDriver != NULL);
108 switch (dwIoControlCode)
110 case IOCTL_USBPRINT_GET_1284_ID:
114 *lpBytesReturned = nOutBufferSize;
115 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
118 case IOCTL_SERIAL_SET_BAUD_RATE:
120 if (pServerSerialDriver->set_baud_rate)
127 SetLastError(ERROR_INVALID_PARAMETER);
131 return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
135 case IOCTL_SERIAL_GET_BAUD_RATE:
137 if (pServerSerialDriver->get_baud_rate)
144 SetLastError(ERROR_INSUFFICIENT_BUFFER);
148 if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
156 case IOCTL_SERIAL_GET_PROPERTIES:
158 if (pServerSerialDriver->get_properties)
162 WINPR_ASSERT(nOutBufferSize >=
sizeof(
COMMPROP));
163 if (nOutBufferSize <
sizeof(
COMMPROP))
165 SetLastError(ERROR_INSUFFICIENT_BUFFER);
169 if (!pServerSerialDriver->get_properties(pComm, pProperties))
172 *lpBytesReturned =
sizeof(
COMMPROP);
177 case IOCTL_SERIAL_SET_CHARS:
179 if (pServerSerialDriver->set_serial_chars)
186 SetLastError(ERROR_INVALID_PARAMETER);
190 return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
194 case IOCTL_SERIAL_GET_CHARS:
196 if (pServerSerialDriver->get_serial_chars)
203 SetLastError(ERROR_INSUFFICIENT_BUFFER);
207 if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
215 case IOCTL_SERIAL_SET_LINE_CONTROL:
217 if (pServerSerialDriver->set_line_control)
224 SetLastError(ERROR_INVALID_PARAMETER);
228 return pServerSerialDriver->set_line_control(pComm, pLineControl);
232 case IOCTL_SERIAL_GET_LINE_CONTROL:
234 if (pServerSerialDriver->get_line_control)
241 SetLastError(ERROR_INSUFFICIENT_BUFFER);
245 if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
253 case IOCTL_SERIAL_SET_HANDFLOW:
255 if (pServerSerialDriver->set_handflow)
262 SetLastError(ERROR_INVALID_PARAMETER);
266 return pServerSerialDriver->set_handflow(pComm, pHandflow);
270 case IOCTL_SERIAL_GET_HANDFLOW:
272 if (pServerSerialDriver->get_handflow)
279 SetLastError(ERROR_INSUFFICIENT_BUFFER);
283 if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
291 case IOCTL_SERIAL_SET_TIMEOUTS:
293 if (pServerSerialDriver->set_timeouts)
300 SetLastError(ERROR_INVALID_PARAMETER);
304 return pServerSerialDriver->set_timeouts(pComm, pHandflow);
308 case IOCTL_SERIAL_GET_TIMEOUTS:
310 if (pServerSerialDriver->get_timeouts)
317 SetLastError(ERROR_INSUFFICIENT_BUFFER);
321 if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
329 case IOCTL_SERIAL_SET_DTR:
331 if (pServerSerialDriver->set_dtr)
333 return pServerSerialDriver->set_dtr(pComm);
337 case IOCTL_SERIAL_CLR_DTR:
339 if (pServerSerialDriver->clear_dtr)
341 return pServerSerialDriver->clear_dtr(pComm);
345 case IOCTL_SERIAL_SET_RTS:
347 if (pServerSerialDriver->set_rts)
349 return pServerSerialDriver->set_rts(pComm);
353 case IOCTL_SERIAL_CLR_RTS:
355 if (pServerSerialDriver->clear_rts)
357 return pServerSerialDriver->clear_rts(pComm);
361 case IOCTL_SERIAL_GET_MODEMSTATUS:
363 if (pServerSerialDriver->get_modemstatus)
365 ULONG* pRegister = (ULONG*)lpOutBuffer;
367 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
368 if (nOutBufferSize <
sizeof(ULONG))
370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
374 if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
377 *lpBytesReturned =
sizeof(ULONG);
382 case IOCTL_SERIAL_SET_WAIT_MASK:
384 if (pServerSerialDriver->set_wait_mask)
386 ULONG* pWaitMask = (ULONG*)lpInBuffer;
388 WINPR_ASSERT(nInBufferSize >=
sizeof(ULONG));
389 if (nInBufferSize <
sizeof(ULONG))
391 SetLastError(ERROR_INVALID_PARAMETER);
395 return pServerSerialDriver->set_wait_mask(pComm, pWaitMask);
399 case IOCTL_SERIAL_GET_WAIT_MASK:
401 if (pServerSerialDriver->get_wait_mask)
403 ULONG* pWaitMask = (ULONG*)lpOutBuffer;
405 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
406 if (nOutBufferSize <
sizeof(ULONG))
408 SetLastError(ERROR_INSUFFICIENT_BUFFER);
412 if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
415 *lpBytesReturned =
sizeof(ULONG);
420 case IOCTL_SERIAL_WAIT_ON_MASK:
422 if (pServerSerialDriver->wait_on_mask)
424 ULONG* pOutputMask = (ULONG*)lpOutBuffer;
426 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
427 if (nOutBufferSize <
sizeof(ULONG))
429 SetLastError(ERROR_INSUFFICIENT_BUFFER);
433 if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask))
435 *lpBytesReturned =
sizeof(ULONG);
439 *lpBytesReturned =
sizeof(ULONG);
444 case IOCTL_SERIAL_SET_QUEUE_SIZE:
446 if (pServerSerialDriver->set_queue_size)
453 SetLastError(ERROR_INVALID_PARAMETER);
457 return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
461 case IOCTL_SERIAL_PURGE:
463 if (pServerSerialDriver->purge)
465 ULONG* pPurgeMask = (ULONG*)lpInBuffer;
467 WINPR_ASSERT(nInBufferSize >=
sizeof(ULONG));
468 if (nInBufferSize <
sizeof(ULONG))
470 SetLastError(ERROR_INVALID_PARAMETER);
474 return pServerSerialDriver->purge(pComm, pPurgeMask);
478 case IOCTL_SERIAL_GET_COMMSTATUS:
480 if (pServerSerialDriver->get_commstatus)
487 SetLastError(ERROR_INSUFFICIENT_BUFFER);
491 if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
499 case IOCTL_SERIAL_SET_BREAK_ON:
501 if (pServerSerialDriver->set_break_on)
503 return pServerSerialDriver->set_break_on(pComm);
507 case IOCTL_SERIAL_SET_BREAK_OFF:
509 if (pServerSerialDriver->set_break_off)
511 return pServerSerialDriver->set_break_off(pComm);
515 case IOCTL_SERIAL_SET_XOFF:
517 if (pServerSerialDriver->set_xoff)
519 return pServerSerialDriver->set_xoff(pComm);
523 case IOCTL_SERIAL_SET_XON:
525 if (pServerSerialDriver->set_xon)
527 return pServerSerialDriver->set_xon(pComm);
531 case IOCTL_SERIAL_GET_DTRRTS:
533 if (pServerSerialDriver->get_dtrrts)
535 ULONG* pMask = (ULONG*)lpOutBuffer;
537 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
538 if (nOutBufferSize <
sizeof(ULONG))
540 SetLastError(ERROR_INSUFFICIENT_BUFFER);
544 if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
547 *lpBytesReturned =
sizeof(ULONG);
552 case IOCTL_SERIAL_CONFIG_SIZE:
554 if (pServerSerialDriver->config_size)
556 ULONG* pSize = (ULONG*)lpOutBuffer;
558 WINPR_ASSERT(nOutBufferSize >=
sizeof(ULONG));
559 if (nOutBufferSize <
sizeof(ULONG))
561 SetLastError(ERROR_INSUFFICIENT_BUFFER);
565 if (!pServerSerialDriver->config_size(pComm, pSize))
568 *lpBytesReturned =
sizeof(ULONG);
573 case IOCTL_SERIAL_IMMEDIATE_CHAR:
575 if (pServerSerialDriver->immediate_char)
577 UCHAR* pChar = (UCHAR*)lpInBuffer;
579 WINPR_ASSERT(nInBufferSize >=
sizeof(UCHAR));
580 if (nInBufferSize <
sizeof(UCHAR))
582 SetLastError(ERROR_INVALID_PARAMETER);
586 return pServerSerialDriver->immediate_char(pComm, pChar);
590 case IOCTL_SERIAL_RESET_DEVICE:
592 if (pServerSerialDriver->reset_device)
594 return pServerSerialDriver->reset_device(pComm);
603 WLOG_WARN, _T(
"unsupported IoControlCode=[0x%08" PRIX32
"] %s (remote serial driver: %s)"),
604 dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name);
605 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
621 BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
622 DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
625 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
628 if (hDevice == INVALID_HANDLE_VALUE)
630 SetLastError(ERROR_INVALID_HANDLE);
634 if (!CommIsHandled(hDevice))
639 SetLastError(ERROR_INVALID_HANDLE);
643 result = s_CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
644 nOutBufferSize, lpBytesReturned, lpOverlapped);
646 if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
649 CommLog_Print(WLOG_WARN,
650 "lpBytesReturned=%" PRIu32
" and nOutBufferSize=%" PRIu32
" are different!",
651 *lpBytesReturned, nOutBufferSize);
654 if (pComm->permissive)
660 "[permissive]: whereas it failed, made to succeed IoControlCode=[0x%08" PRIX32
661 "] %s, last-error: 0x%08" PRIX32
"",
662 dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError());
671 int _comm_ioctl_tcsetattr(
int fd,
int optional_actions,
const struct termios* termios_p)
674 struct termios currentState = { 0 };
676 if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
678 CommLog_Print(WLOG_WARN,
"tcsetattr failure, errno: %d", errno);
683 if ((result = tcgetattr(fd, ¤tState)) < 0)
685 CommLog_Print(WLOG_WARN,
"tcgetattr failure, errno: %d", errno);
690 if (memcmp(¤tState, termios_p,
sizeof(
struct termios)) != 0)
692 CommLog_Print(WLOG_DEBUG,
693 "all termios parameters are not set yet, doing a second attempt...");
694 if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
696 CommLog_Print(WLOG_WARN,
"2nd tcsetattr failure, errno: %d", errno);
700 ZeroMemory(¤tState,
sizeof(
struct termios));
701 if ((result = tcgetattr(fd, ¤tState)) < 0)
703 CommLog_Print(WLOG_WARN,
"tcgetattr failure, errno: %d", errno);
708 if (memcmp(¤tState, termios_p,
sizeof(
struct termios)) != 0)
710 CommLog_Print(WLOG_WARN,
711 "Failure: all termios parameters are still not set on a second attempt");