VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/serialport-win.cpp@ 69982

Last change on this file since 69982 was 69982, checked in by vboxsync, 7 years ago

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: serialport-win.cpp 69982 2017-12-07 14:22:30Z vboxsync $ */
2/** @file
3 * IPRT - Serial Port API, Windows Implementation.
4 */
5
6/*
7 * Copyright (C) 2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/serialport.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/cdefs.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42#include "internal/magics.h"
43
44#include <iprt/win/windows.h>
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50
51/**
52 * Internal serial port state.
53 */
54typedef struct RTSERIALPORTINTERNAL
55{
56 /** Magic value (RTSERIALPORT_MAGIC). */
57 uint32_t u32Magic;
58 /** Flags given while opening the serial port. */
59 uint32_t fOpenFlags;
60 /** The device handle. */
61 HANDLE hDev;
62 /** The overlapped I/O structure. */
63 OVERLAPPED Overlapped;
64 /** The event handle to wait on for the overlapped I/O operations of the device. */
65 HANDLE hEvtDev;
66 /** The event handle to wait on for waking up waiting threads externally. */
67 HANDLE hEvtIntr;
68 /** Events currently waited for. */
69 uint32_t fEvtMask;
70 /** Flag whether a write is currently pending. */
71 bool fWritePending;
72 /** Bounce buffer for writes. */
73 uint8_t *pbBounceBuf;
74 /** Amount of used buffer space. */
75 size_t cbBounceBufUsed;
76 /** Amount of allocated buffer space. */
77 size_t cbBounceBufAlloc;
78 /** The current active port config. */
79 DCB PortCfg;
80} RTSERIALPORTINTERNAL;
81/** Pointer to the internal serial port state. */
82typedef RTSERIALPORTINTERNAL *PRTSERIALPORTINTERNAL;
83
84
85
86/*********************************************************************************************************************************
87* Defined Constants And Macros *
88*********************************************************************************************************************************/
89/** The pipe buffer size we prefer. */
90#define RTSERIALPORT_NT_SIZE _32K
91
92
93
94/*********************************************************************************************************************************
95* Global variables *
96*********************************************************************************************************************************/
97
98
99
100/*********************************************************************************************************************************
101* Internal Functions *
102*********************************************************************************************************************************/
103
104/**
105 * Updatest the current event mask to wait for.
106 *
107 * @returns IPRT status code.
108 * @param pThis The internal serial port instance data.
109 * @param fEvtMask The new event mask to change to.
110 */
111static int rtSerialPortWinUpdateEvtMask(PRTSERIALPORTINTERNAL pThis, uint32_t fEvtMask)
112{
113 DWORD dwEvtMask = 0;
114
115 if (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX)
116 dwEvtMask |= EV_RXCHAR;
117 if (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX)
118 dwEvtMask |= EV_TXEMPTY;
119 if (fEvtMask & RTSERIALPORT_EVT_F_BREAK_DETECTED)
120 dwEvtMask |= EV_BREAK;
121 if (fEvtMask & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
122 dwEvtMask |= EV_CTS | EV_DSR | EV_RING | EV_RLSD;
123
124 int rc = VINF_SUCCESS;
125 if (!SetCommMask(pThis->hDev, dwEvtMask))
126 rc = RTErrConvertFromWin32(GetLastError());
127 else
128 pThis->fEvtMask = fEvtMask;
129
130 return rc;
131}
132
133
134/**
135 * Tries to set the default config on the given serial port.
136 *
137 * @returns IPRT status code.
138 * @param pThis The internal serial port instance data.
139 */
140static int rtSerialPortSetDefaultCfg(PRTSERIALPORTINTERNAL pThis)
141{
142 if (!PurgeComm(pThis->hDev, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
143 return RTErrConvertFromWin32(GetLastError());
144
145 pThis->PortCfg.DCBlength = sizeof(pThis->PortCfg);
146 if (!GetCommState(pThis->hDev, &pThis->PortCfg))
147 return RTErrConvertFromWin32(GetLastError());
148
149 pThis->PortCfg.BaudRate = CBR_9600;
150 pThis->PortCfg.fBinary = TRUE;
151 pThis->PortCfg.fParity = TRUE;
152 pThis->PortCfg.fDtrControl = DTR_CONTROL_DISABLE;
153 pThis->PortCfg.ByteSize = 8;
154 pThis->PortCfg.Parity = NOPARITY;
155
156 int rc = VINF_SUCCESS;
157 if (!SetCommState(pThis->hDev, &pThis->PortCfg))
158 rc = RTErrConvertFromWin32(GetLastError());
159
160 return rc;
161}
162
163
164/**
165 * Common worker for handling I/O completion.
166 *
167 * This is used by RTSerialPortClose, RTSerialPortWrite and RTPipeSerialPortNB.
168 *
169 * @returns IPRT status code.
170 * @param pThis The pipe instance handle.
171 */
172static int rtSerialPortWriteCheckCompletion(PRTSERIALPORTINTERNAL pThis)
173{
174 int rc = VINF_SUCCESS;
175 DWORD dwRc = WaitForSingleObject(pThis->Overlapped.hEvent, 0);
176 if (dwRc == WAIT_OBJECT_0)
177 {
178 DWORD cbWritten = 0;
179 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbWritten, TRUE))
180 {
181 for (;;)
182 {
183 if (cbWritten >= pThis->cbBounceBufUsed)
184 {
185 pThis->fWritePending = false;
186 rc = VINF_SUCCESS;
187 break;
188 }
189
190 /* resubmit the remainder of the buffer - can this actually happen? */
191 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
192 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
193 if (!WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
194 &cbWritten, &pThis->Overlapped))
195 {
196 if (GetLastError() == ERROR_IO_PENDING)
197 rc = VINF_TRY_AGAIN;
198 else
199 {
200 pThis->fWritePending = false;
201 rc = RTErrConvertFromWin32(GetLastError());
202 }
203 break;
204 }
205 Assert(cbWritten > 0);
206 }
207 }
208 else
209 {
210 pThis->fWritePending = false;
211 rc = RTErrConvertFromWin32(GetLastError());
212 }
213 }
214 else if (dwRc == WAIT_TIMEOUT)
215 rc = VINF_TRY_AGAIN;
216 else
217 {
218 pThis->fWritePending = false;
219 if (dwRc == WAIT_ABANDONED)
220 rc = VERR_INVALID_HANDLE;
221 else
222 rc = RTErrConvertFromWin32(GetLastError());
223 }
224 return rc;
225}
226
227
228RTDECL(int) RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags)
229{
230 AssertPtrReturn(phSerialPort, VERR_INVALID_POINTER);
231 AssertReturn(VALID_PTR(pszPortAddress) && *pszPortAddress != '\0', VERR_INVALID_PARAMETER);
232 AssertReturn(!(fFlags & ~RTSERIALPORT_OPEN_F_VALID_MASK), VERR_INVALID_PARAMETER);
233 AssertReturn((fFlags & RTSERIALPORT_OPEN_F_READ) || (fFlags & RTSERIALPORT_OPEN_F_WRITE),
234 VERR_INVALID_PARAMETER);
235
236 int rc = VINF_SUCCESS;
237 PRTSERIALPORTINTERNAL pThis = (PRTSERIALPORTINTERNAL)RTMemAllocZ(sizeof(*pThis));
238 if (pThis)
239 {
240 pThis->fOpenFlags = fFlags;
241 pThis->fEvtMask = 0;
242 pThis->fWritePending = false;
243 pThis->pbBounceBuf = NULL;
244 pThis->cbBounceBufUsed = 0;
245 pThis->cbBounceBufAlloc = 0;
246 pThis->hEvtDev = CreateEvent(NULL, FALSE, FALSE, NULL);
247 if (pThis->hEvtDev)
248 {
249 pThis->Overlapped.hEvent = pThis->hEvtDev,
250 pThis->hEvtIntr = CreateEvent(NULL, FALSE, FALSE, NULL);
251 if (pThis->hEvtIntr)
252 {
253 DWORD fWinFlags = 0;
254
255 if (fFlags & RTSERIALPORT_OPEN_F_WRITE)
256 fWinFlags |= GENERIC_WRITE;
257 if (fFlags & RTSERIALPORT_OPEN_F_READ)
258 fWinFlags |= GENERIC_READ;
259
260 pThis->hDev = CreateFile(pszPortAddress,
261 fWinFlags,
262 0, /* Must be opened with exclusive access. */
263 NULL, /* No SECURITY_ATTRIBUTES structure. */
264 OPEN_EXISTING, /* Must use OPEN_EXISTING. */
265 FILE_FLAG_OVERLAPPED, /* Overlapped I/O. */
266 NULL);
267 if (pThis->hDev)
268 rc = rtSerialPortSetDefaultCfg(pThis);
269 else
270 rc = RTErrConvertFromWin32(GetLastError());
271
272 CloseHandle(pThis->hEvtDev);
273 }
274 else
275 rc = RTErrConvertFromWin32(GetLastError());
276
277 CloseHandle(pThis->hEvtDev);
278 }
279 else
280 rc = RTErrConvertFromWin32(GetLastError());
281
282 RTMemFree(pThis);
283 }
284 else
285 rc = VERR_NO_MEMORY;
286
287 return rc;
288}
289
290
291RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort)
292{
293 PRTSERIALPORTINTERNAL pThis = hSerialPort;
294 if (pThis == NIL_RTSERIALPORT)
295 return VINF_SUCCESS;
296 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
297 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
298
299 /*
300 * Do the cleanup.
301 */
302 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE);
303
304 if (pThis->fWritePending)
305 rtSerialPortWriteCheckCompletion(pThis);
306
307 CloseHandle(pThis->hDev);
308 CloseHandle(pThis->hEvtDev);
309 CloseHandle(pThis->hEvtIntr);
310 pThis->hDev = NULL;
311 pThis->hEvtDev = NULL;
312 pThis->hEvtIntr = NULL;
313 RTMemFree(pThis);
314 return VINF_SUCCESS;
315}
316
317
318RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort)
319{
320 PRTSERIALPORTINTERNAL pThis = hSerialPort;
321 AssertPtrReturn(pThis, -1);
322 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, -1);
323
324 return (RTHCINTPTR)pThis->hDev;
325}
326
327
328RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
329{
330 PRTSERIALPORTINTERNAL pThis = hSerialPort;
331 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
332 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
333 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
334 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
335
336 RT_NOREF(pcbRead);
337 int rc = VERR_NOT_IMPLEMENTED;
338 return rc;
339}
340
341
342RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
343{
344 PRTSERIALPORTINTERNAL pThis = hSerialPort;
345 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
346 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
347 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
348 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
349 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
350
351 *pcbRead = 0;
352
353 /*
354 * Kick of an overlapped read. It should return immediately if
355 * there is bytes in the buffer. If not, we'll cancel it and see
356 * what we get back.
357 */
358 int rc = VINF_SUCCESS;
359 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
360 DWORD cbRead = 0;
361 if ( cbToRead == 0
362 || ReadFile(pThis->hDev, pvBuf,
363 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
364 &cbRead, &pThis->Overlapped))
365 {
366 *pcbRead = cbRead;
367 rc = VINF_SUCCESS;
368 }
369 else if (GetLastError() == ERROR_IO_PENDING)
370 {
371 if (!CancelIo(pThis->hDev))
372 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
373 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
374 {
375 *pcbRead = cbRead;
376 rc = VINF_SUCCESS;
377 }
378 else if (GetLastError() == ERROR_OPERATION_ABORTED)
379 {
380 *pcbRead = 0;
381 rc = VINF_TRY_AGAIN;
382 }
383 else
384 rc = RTErrConvertFromWin32(GetLastError());
385 }
386 else
387 rc = RTErrConvertFromWin32(GetLastError());
388
389 return rc;
390}
391
392
393RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
394{
395 RT_NOREF(hSerialPort, pvBuf, cbToWrite, pcbWritten);
396 return VERR_NOT_IMPLEMENTED;
397}
398
399
400RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
401{
402 PRTSERIALPORTINTERNAL pThis = hSerialPort;
403 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
404 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
405 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
406 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
407 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
408
409 /* If I/O is pending, check if it has completed. */
410 int rc = VINF_SUCCESS;
411 if (pThis->fWritePending)
412 rc = rtSerialPortWriteCheckCompletion(pThis);
413 if (rc == VINF_SUCCESS)
414 {
415 Assert(!pThis->fWritePending);
416
417 /* Do the bounce buffering. */
418 if ( pThis->cbBounceBufAlloc < cbToWrite
419 && pThis->cbBounceBufAlloc < RTSERIALPORT_NT_SIZE)
420 {
421 if (cbToWrite > RTSERIALPORT_NT_SIZE)
422 cbToWrite = RTSERIALPORT_NT_SIZE;
423 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K));
424 if (pv)
425 {
426 pThis->pbBounceBuf = (uint8_t *)pv;
427 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K);
428 }
429 else
430 rc = VERR_NO_MEMORY;
431 }
432 else if (cbToWrite > RTSERIALPORT_NT_SIZE)
433 cbToWrite = RTSERIALPORT_NT_SIZE;
434 if (RT_SUCCESS(rc) && cbToWrite)
435 {
436 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite);
437 pThis->cbBounceBufUsed = (uint32_t)cbToWrite;
438
439 /* Submit the write. */
440 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
441 DWORD cbWritten = 0;
442 if (WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
443 &cbWritten, &pThis->Overlapped))
444 {
445 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */
446 rc = VINF_SUCCESS;
447 }
448 else if (GetLastError() == ERROR_IO_PENDING)
449 {
450 *pcbWritten = cbToWrite;
451 pThis->fWritePending = true;
452 rc = VINF_SUCCESS;
453 }
454 else
455 rc = RTErrConvertFromWin32(GetLastError());
456 }
457 else if (RT_SUCCESS(rc))
458 *pcbWritten = 0;
459 }
460 else if (RT_SUCCESS(rc))
461 *pcbWritten = 0;
462
463 return rc;
464}
465
466
467RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg)
468{
469 PRTSERIALPORTINTERNAL pThis = hSerialPort;
470 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
471 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
472
473 pCfg->uBaudRate = pThis->PortCfg.BaudRate;
474 switch (pThis->PortCfg.Parity)
475 {
476 case NOPARITY:
477 pCfg->enmParity = RTSERIALPORTPARITY_NONE;
478 break;
479 case EVENPARITY:
480 pCfg->enmParity = RTSERIALPORTPARITY_EVEN;
481 break;
482 case ODDPARITY:
483 pCfg->enmParity = RTSERIALPORTPARITY_ODD;
484 break;
485 case MARKPARITY:
486 pCfg->enmParity = RTSERIALPORTPARITY_MARK;
487 break;
488 case SPACEPARITY:
489 pCfg->enmParity = RTSERIALPORTPARITY_SPACE;
490 break;
491 default:
492 AssertFailed();
493 return VERR_INTERNAL_ERROR;
494 }
495
496 switch (pThis->PortCfg.ByteSize)
497 {
498 case 5:
499 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
500 break;
501 case 6:
502 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
503 break;
504 case 7:
505 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
506 break;
507 case 8:
508 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
509 break;
510 default:
511 AssertFailed();
512 return VERR_INTERNAL_ERROR;
513 }
514
515 switch (pThis->PortCfg.StopBits)
516 {
517 case ONESTOPBIT:
518 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
519 break;
520 case ONE5STOPBITS:
521 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
522 break;
523 case TWOSTOPBITS:
524 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
525 break;
526 default:
527 AssertFailed();
528 return VERR_INTERNAL_ERROR;
529 }
530
531 return VINF_SUCCESS;
532}
533
534
535RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo)
536{
537 PRTSERIALPORTINTERNAL pThis = hSerialPort;
538 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
539 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
540
541 RT_NOREF(pErrInfo);
542
543 DCB DcbNew;
544 memcpy(&DcbNew, &pThis->PortCfg, sizeof(DcbNew));
545 DcbNew.BaudRate = pCfg->uBaudRate;
546
547 switch (pCfg->enmParity)
548 {
549 case RTSERIALPORTPARITY_NONE:
550 DcbNew.Parity = NOPARITY;
551 break;
552 case RTSERIALPORTPARITY_EVEN:
553 DcbNew.Parity = EVENPARITY;
554 break;
555 case RTSERIALPORTPARITY_ODD:
556 DcbNew.Parity = ODDPARITY;
557 break;
558 case RTSERIALPORTPARITY_MARK:
559 DcbNew.Parity = MARKPARITY;
560 break;
561 case RTSERIALPORTPARITY_SPACE:
562 DcbNew.Parity = SPACEPARITY;
563 break;
564 default:
565 AssertFailedReturn(VERR_INVALID_PARAMETER);
566 }
567
568 switch (pCfg->enmDataBitCount)
569 {
570 case RTSERIALPORTDATABITS_5BITS:
571 DcbNew.ByteSize = 5;
572 break;
573 case RTSERIALPORTDATABITS_6BITS:
574 DcbNew.ByteSize = 6;
575 break;
576 case RTSERIALPORTDATABITS_7BITS:
577 DcbNew.ByteSize = 7;
578 break;
579 case RTSERIALPORTDATABITS_8BITS:
580 DcbNew.ByteSize = 8;
581 break;
582 default:
583 AssertFailedReturn(VERR_INVALID_PARAMETER);
584 }
585
586 switch (pCfg->enmStopBitCount)
587 {
588 case RTSERIALPORTSTOPBITS_ONE:
589 DcbNew.StopBits = ONESTOPBIT;
590 break;
591 case RTSERIALPORTSTOPBITS_ONEPOINTFIVE:
592 AssertReturn(pCfg->enmDataBitCount == RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
593 DcbNew.StopBits = ONE5STOPBITS;
594 break;
595 case RTSERIALPORTSTOPBITS_TWO:
596 AssertReturn(pCfg->enmDataBitCount != RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
597 DcbNew.StopBits = TWOSTOPBITS;
598 break;
599 default:
600 AssertFailedReturn(VERR_INVALID_PARAMETER);
601 }
602
603 int rc = VINF_SUCCESS;
604 if (!SetCommState(pThis->hDev, &DcbNew))
605 rc = RTErrConvertFromWin32(GetLastError());
606 else
607 memcpy(&pThis->PortCfg, &DcbNew, sizeof(DcbNew));
608
609 return rc;
610}
611
612
613RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv,
614 RTMSINTERVAL msTimeout)
615{
616 PRTSERIALPORTINTERNAL pThis = hSerialPort;
617 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
618 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
619 AssertReturn(!(fEvtMask & ~RTSERIALPORT_EVT_F_VALID_MASK), VERR_INVALID_PARAMETER);
620 AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER);
621
622 *pfEvtsRecv = 0;
623
624 int rc = VINF_SUCCESS;
625 if (fEvtMask != pThis->fEvtMask)
626 rc = rtSerialPortWinUpdateEvtMask(pThis, fEvtMask);
627
628 if (RT_SUCCESS(rc))
629 {
630 DWORD dwEventMask = 0;
631 HANDLE ahWait[2];
632 ahWait[0] = pThis->hEvtDev;
633 ahWait[1] = pThis->hEvtIntr;
634
635 RT_ZERO(pThis->Overlapped);
636 pThis->Overlapped.hEvent = pThis->hEvtDev;
637
638 if (!WaitCommEvent(pThis->hDev, &dwEventMask, &pThis->Overlapped))
639 {
640 DWORD dwRet = GetLastError();
641 if (dwRet == ERROR_IO_PENDING)
642 {
643 dwRet = WaitForMultipleObjects(2, ahWait, FALSE, msTimeout == RT_INDEFINITE_WAIT ? INFINITE : msTimeout);
644 if (dwRet == WAIT_TIMEOUT)
645 rc = VERR_TIMEOUT;
646 else if (dwRet == WAIT_FAILED)
647 rc = RTErrConvertFromWin32(GetLastError());
648 else if (dwRet != WAIT_OBJECT_0)
649 rc = VERR_INTERRUPTED;
650 }
651 else
652 rc = RTErrConvertFromWin32(dwRet);
653 }
654
655 if (RT_SUCCESS(rc))
656 {
657 /* Check the event */
658 if (dwEventMask & EV_RXCHAR)
659 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_RX;
660 if (dwEventMask & EV_TXEMPTY)
661 {
662 if (pThis->fWritePending)
663 {
664 rc = rtSerialPortWriteCheckCompletion(pThis);
665 if (rc == VINF_SUCCESS)
666 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
667 else
668 rc = VINF_SUCCESS;
669 }
670 else
671 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
672 }
673 if (dwEventMask & EV_BREAK)
674 *pfEvtsRecv |= RTSERIALPORT_EVT_F_BREAK_DETECTED;
675 if (dwEventMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD))
676 *pfEvtsRecv |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
677 }
678 }
679
680 return rc;
681}
682
683
684RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort)
685{
686 PRTSERIALPORTINTERNAL pThis = hSerialPort;
687 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
688 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
689
690 if (!SetEvent(pThis->hEvtIntr))
691 return RTErrConvertFromWin32(GetLastError());
692
693 return VINF_SUCCESS;
694}
695
696
697RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet)
698{
699 PRTSERIALPORTINTERNAL pThis = hSerialPort;
700 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
701 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
702
703 BOOL fSucc = FALSE;
704 if (fSet)
705 fSucc = SetCommBreak(pThis->hDev);
706 else
707 fSucc = ClearCommBreak(pThis->hDev);
708
709 int rc = VINF_SUCCESS;
710 if (!fSucc)
711 rc = RTErrConvertFromWin32(GetLastError());
712
713 return rc;
714}
715
716
717RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet)
718{
719 PRTSERIALPORTINTERNAL pThis = hSerialPort;
720 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
721 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
722
723 BOOL fSucc = TRUE;
724 if (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR)
725 fSucc = EscapeCommFunction(pThis->hDev, SETDTR);
726 if ( fSucc
727 && (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS))
728 fSucc = EscapeCommFunction(pThis->hDev, SETRTS);
729
730 if ( fSucc
731 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR))
732 fSucc = EscapeCommFunction(pThis->hDev, CLRDTR);
733 if ( fSucc
734 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS))
735 fSucc = EscapeCommFunction(pThis->hDev, CLRRTS);
736
737 int rc = VINF_SUCCESS;
738 if (!fSucc)
739 rc = RTErrConvertFromWin32(GetLastError());
740
741 return rc;
742}
743
744
745RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines)
746{
747 PRTSERIALPORTINTERNAL pThis = hSerialPort;
748 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
749 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
750 AssertPtrReturn(pfStsLines, VERR_INVALID_POINTER);
751
752 *pfStsLines = 0;
753
754 int rc = VINF_SUCCESS;
755 DWORD fStsLinesQueried = 0;
756
757 /* Get the new state */
758 if (GetCommModemStatus(pThis->hDev, &fStsLinesQueried))
759 {
760 *pfStsLines |= (fStsLinesQueried & MS_RLSD_ON) ? RTSERIALPORT_STS_LINE_DCD : 0;
761 *pfStsLines |= (fStsLinesQueried & MS_RING_ON) ? RTSERIALPORT_STS_LINE_RI : 0;
762 *pfStsLines |= (fStsLinesQueried & MS_DSR_ON) ? RTSERIALPORT_STS_LINE_DSR : 0;
763 *pfStsLines |= (fStsLinesQueried & MS_CTS_ON) ? RTSERIALPORT_STS_LINE_CTS : 0;
764 }
765 else
766 rc = RTErrConvertFromWin32(GetLastError());
767
768 return rc;
769}
770
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette