VirtualBox

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

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

Runtime/RTSerialPort: POSIX and Windows implementation fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.8 KB
Line 
1/* $Id: serialport-win.cpp 69986 2017-12-07 15:46:42Z 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->u32Magic = RTSERIALPORT_MAGIC;
241 pThis->fOpenFlags = fFlags;
242 pThis->fEvtMask = 0;
243 pThis->fWritePending = false;
244 pThis->pbBounceBuf = NULL;
245 pThis->cbBounceBufUsed = 0;
246 pThis->cbBounceBufAlloc = 0;
247 pThis->hEvtDev = CreateEvent(NULL, FALSE, FALSE, NULL);
248 if (pThis->hEvtDev)
249 {
250 pThis->Overlapped.hEvent = pThis->hEvtDev,
251 pThis->hEvtIntr = CreateEvent(NULL, FALSE, FALSE, NULL);
252 if (pThis->hEvtIntr)
253 {
254 DWORD fWinFlags = 0;
255
256 if (fFlags & RTSERIALPORT_OPEN_F_WRITE)
257 fWinFlags |= GENERIC_WRITE;
258 if (fFlags & RTSERIALPORT_OPEN_F_READ)
259 fWinFlags |= GENERIC_READ;
260
261 pThis->hDev = CreateFile(pszPortAddress,
262 fWinFlags,
263 0, /* Must be opened with exclusive access. */
264 NULL, /* No SECURITY_ATTRIBUTES structure. */
265 OPEN_EXISTING, /* Must use OPEN_EXISTING. */
266 FILE_FLAG_OVERLAPPED, /* Overlapped I/O. */
267 NULL);
268 if (pThis->hDev)
269 rc = rtSerialPortSetDefaultCfg(pThis);
270 else
271 rc = RTErrConvertFromWin32(GetLastError());
272
273 CloseHandle(pThis->hEvtDev);
274 }
275 else
276 rc = RTErrConvertFromWin32(GetLastError());
277
278 CloseHandle(pThis->hEvtDev);
279 }
280 else
281 rc = RTErrConvertFromWin32(GetLastError());
282
283 RTMemFree(pThis);
284 }
285 else
286 rc = VERR_NO_MEMORY;
287
288 return rc;
289}
290
291
292RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort)
293{
294 PRTSERIALPORTINTERNAL pThis = hSerialPort;
295 if (pThis == NIL_RTSERIALPORT)
296 return VINF_SUCCESS;
297 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
298 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
299
300 /*
301 * Do the cleanup.
302 */
303 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE);
304
305 if (pThis->fWritePending)
306 rtSerialPortWriteCheckCompletion(pThis);
307
308 CloseHandle(pThis->hDev);
309 CloseHandle(pThis->hEvtDev);
310 CloseHandle(pThis->hEvtIntr);
311 pThis->hDev = NULL;
312 pThis->hEvtDev = NULL;
313 pThis->hEvtIntr = NULL;
314 RTMemFree(pThis);
315 return VINF_SUCCESS;
316}
317
318
319RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort)
320{
321 PRTSERIALPORTINTERNAL pThis = hSerialPort;
322 AssertPtrReturn(pThis, -1);
323 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, -1);
324
325 return (RTHCINTPTR)pThis->hDev;
326}
327
328
329RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
330{
331 PRTSERIALPORTINTERNAL pThis = hSerialPort;
332 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
333 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
334 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
335 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
336
337 RT_NOREF(pcbRead);
338 int rc = VERR_NOT_IMPLEMENTED;
339 return rc;
340}
341
342
343RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
344{
345 PRTSERIALPORTINTERNAL pThis = hSerialPort;
346 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
347 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
348 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
349 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
350 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
351
352 *pcbRead = 0;
353
354 /*
355 * Kick of an overlapped read. It should return immediately if
356 * there is bytes in the buffer. If not, we'll cancel it and see
357 * what we get back.
358 */
359 int rc = VINF_SUCCESS;
360 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
361 DWORD cbRead = 0;
362 if ( cbToRead == 0
363 || ReadFile(pThis->hDev, pvBuf,
364 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
365 &cbRead, &pThis->Overlapped))
366 {
367 *pcbRead = cbRead;
368 rc = VINF_SUCCESS;
369 }
370 else if (GetLastError() == ERROR_IO_PENDING)
371 {
372 if (!CancelIo(pThis->hDev))
373 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
374 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
375 {
376 *pcbRead = cbRead;
377 rc = VINF_SUCCESS;
378 }
379 else if (GetLastError() == ERROR_OPERATION_ABORTED)
380 {
381 *pcbRead = 0;
382 rc = VINF_TRY_AGAIN;
383 }
384 else
385 rc = RTErrConvertFromWin32(GetLastError());
386 }
387 else
388 rc = RTErrConvertFromWin32(GetLastError());
389
390 return rc;
391}
392
393
394RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
395{
396 RT_NOREF(hSerialPort, pvBuf, cbToWrite, pcbWritten);
397 return VERR_NOT_IMPLEMENTED;
398}
399
400
401RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
402{
403 PRTSERIALPORTINTERNAL pThis = hSerialPort;
404 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
405 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
406 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
407 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
408 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
409
410 /* If I/O is pending, check if it has completed. */
411 int rc = VINF_SUCCESS;
412 if (pThis->fWritePending)
413 rc = rtSerialPortWriteCheckCompletion(pThis);
414 if (rc == VINF_SUCCESS)
415 {
416 Assert(!pThis->fWritePending);
417
418 /* Do the bounce buffering. */
419 if ( pThis->cbBounceBufAlloc < cbToWrite
420 && pThis->cbBounceBufAlloc < RTSERIALPORT_NT_SIZE)
421 {
422 if (cbToWrite > RTSERIALPORT_NT_SIZE)
423 cbToWrite = RTSERIALPORT_NT_SIZE;
424 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K));
425 if (pv)
426 {
427 pThis->pbBounceBuf = (uint8_t *)pv;
428 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K);
429 }
430 else
431 rc = VERR_NO_MEMORY;
432 }
433 else if (cbToWrite > RTSERIALPORT_NT_SIZE)
434 cbToWrite = RTSERIALPORT_NT_SIZE;
435 if (RT_SUCCESS(rc) && cbToWrite)
436 {
437 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite);
438 pThis->cbBounceBufUsed = (uint32_t)cbToWrite;
439
440 /* Submit the write. */
441 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
442 DWORD cbWritten = 0;
443 if (WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
444 &cbWritten, &pThis->Overlapped))
445 {
446 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */
447 rc = VINF_SUCCESS;
448 }
449 else if (GetLastError() == ERROR_IO_PENDING)
450 {
451 *pcbWritten = cbToWrite;
452 pThis->fWritePending = true;
453 rc = VINF_SUCCESS;
454 }
455 else
456 rc = RTErrConvertFromWin32(GetLastError());
457 }
458 else if (RT_SUCCESS(rc))
459 *pcbWritten = 0;
460 }
461 else if (RT_SUCCESS(rc))
462 *pcbWritten = 0;
463
464 return rc;
465}
466
467
468RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg)
469{
470 PRTSERIALPORTINTERNAL pThis = hSerialPort;
471 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
472 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
473
474 pCfg->uBaudRate = pThis->PortCfg.BaudRate;
475 switch (pThis->PortCfg.Parity)
476 {
477 case NOPARITY:
478 pCfg->enmParity = RTSERIALPORTPARITY_NONE;
479 break;
480 case EVENPARITY:
481 pCfg->enmParity = RTSERIALPORTPARITY_EVEN;
482 break;
483 case ODDPARITY:
484 pCfg->enmParity = RTSERIALPORTPARITY_ODD;
485 break;
486 case MARKPARITY:
487 pCfg->enmParity = RTSERIALPORTPARITY_MARK;
488 break;
489 case SPACEPARITY:
490 pCfg->enmParity = RTSERIALPORTPARITY_SPACE;
491 break;
492 default:
493 AssertFailed();
494 return VERR_INTERNAL_ERROR;
495 }
496
497 switch (pThis->PortCfg.ByteSize)
498 {
499 case 5:
500 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
501 break;
502 case 6:
503 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
504 break;
505 case 7:
506 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
507 break;
508 case 8:
509 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
510 break;
511 default:
512 AssertFailed();
513 return VERR_INTERNAL_ERROR;
514 }
515
516 switch (pThis->PortCfg.StopBits)
517 {
518 case ONESTOPBIT:
519 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
520 break;
521 case ONE5STOPBITS:
522 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
523 break;
524 case TWOSTOPBITS:
525 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
526 break;
527 default:
528 AssertFailed();
529 return VERR_INTERNAL_ERROR;
530 }
531
532 return VINF_SUCCESS;
533}
534
535
536RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo)
537{
538 PRTSERIALPORTINTERNAL pThis = hSerialPort;
539 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
540 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
541
542 RT_NOREF(pErrInfo);
543
544 DCB DcbNew;
545 memcpy(&DcbNew, &pThis->PortCfg, sizeof(DcbNew));
546 DcbNew.BaudRate = pCfg->uBaudRate;
547
548 switch (pCfg->enmParity)
549 {
550 case RTSERIALPORTPARITY_NONE:
551 DcbNew.Parity = NOPARITY;
552 break;
553 case RTSERIALPORTPARITY_EVEN:
554 DcbNew.Parity = EVENPARITY;
555 break;
556 case RTSERIALPORTPARITY_ODD:
557 DcbNew.Parity = ODDPARITY;
558 break;
559 case RTSERIALPORTPARITY_MARK:
560 DcbNew.Parity = MARKPARITY;
561 break;
562 case RTSERIALPORTPARITY_SPACE:
563 DcbNew.Parity = SPACEPARITY;
564 break;
565 default:
566 AssertFailedReturn(VERR_INVALID_PARAMETER);
567 }
568
569 switch (pCfg->enmDataBitCount)
570 {
571 case RTSERIALPORTDATABITS_5BITS:
572 DcbNew.ByteSize = 5;
573 break;
574 case RTSERIALPORTDATABITS_6BITS:
575 DcbNew.ByteSize = 6;
576 break;
577 case RTSERIALPORTDATABITS_7BITS:
578 DcbNew.ByteSize = 7;
579 break;
580 case RTSERIALPORTDATABITS_8BITS:
581 DcbNew.ByteSize = 8;
582 break;
583 default:
584 AssertFailedReturn(VERR_INVALID_PARAMETER);
585 }
586
587 switch (pCfg->enmStopBitCount)
588 {
589 case RTSERIALPORTSTOPBITS_ONE:
590 DcbNew.StopBits = ONESTOPBIT;
591 break;
592 case RTSERIALPORTSTOPBITS_ONEPOINTFIVE:
593 AssertReturn(pCfg->enmDataBitCount == RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
594 DcbNew.StopBits = ONE5STOPBITS;
595 break;
596 case RTSERIALPORTSTOPBITS_TWO:
597 AssertReturn(pCfg->enmDataBitCount != RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
598 DcbNew.StopBits = TWOSTOPBITS;
599 break;
600 default:
601 AssertFailedReturn(VERR_INVALID_PARAMETER);
602 }
603
604 int rc = VINF_SUCCESS;
605 if (!SetCommState(pThis->hDev, &DcbNew))
606 rc = RTErrConvertFromWin32(GetLastError());
607 else
608 memcpy(&pThis->PortCfg, &DcbNew, sizeof(DcbNew));
609
610 return rc;
611}
612
613
614RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv,
615 RTMSINTERVAL msTimeout)
616{
617 PRTSERIALPORTINTERNAL pThis = hSerialPort;
618 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
619 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
620 AssertReturn(!(fEvtMask & ~RTSERIALPORT_EVT_F_VALID_MASK), VERR_INVALID_PARAMETER);
621 AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER);
622
623 *pfEvtsRecv = 0;
624
625 int rc = VINF_SUCCESS;
626 if (fEvtMask != pThis->fEvtMask)
627 rc = rtSerialPortWinUpdateEvtMask(pThis, fEvtMask);
628
629 if (RT_SUCCESS(rc))
630 {
631 DWORD dwEventMask = 0;
632 HANDLE ahWait[2];
633 ahWait[0] = pThis->hEvtDev;
634 ahWait[1] = pThis->hEvtIntr;
635
636 RT_ZERO(pThis->Overlapped);
637 pThis->Overlapped.hEvent = pThis->hEvtDev;
638
639 if (!WaitCommEvent(pThis->hDev, &dwEventMask, &pThis->Overlapped))
640 {
641 DWORD dwRet = GetLastError();
642 if (dwRet == ERROR_IO_PENDING)
643 {
644 dwRet = WaitForMultipleObjects(2, ahWait, FALSE, msTimeout == RT_INDEFINITE_WAIT ? INFINITE : msTimeout);
645 if (dwRet == WAIT_TIMEOUT)
646 rc = VERR_TIMEOUT;
647 else if (dwRet == WAIT_FAILED)
648 rc = RTErrConvertFromWin32(GetLastError());
649 else if (dwRet != WAIT_OBJECT_0)
650 rc = VERR_INTERRUPTED;
651 }
652 else
653 rc = RTErrConvertFromWin32(dwRet);
654 }
655
656 if (RT_SUCCESS(rc))
657 {
658 /* Check the event */
659 if (dwEventMask & EV_RXCHAR)
660 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_RX;
661 if (dwEventMask & EV_TXEMPTY)
662 {
663 if (pThis->fWritePending)
664 {
665 rc = rtSerialPortWriteCheckCompletion(pThis);
666 if (rc == VINF_SUCCESS)
667 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
668 else
669 rc = VINF_SUCCESS;
670 }
671 else
672 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
673 }
674 if (dwEventMask & EV_BREAK)
675 *pfEvtsRecv |= RTSERIALPORT_EVT_F_BREAK_DETECTED;
676 if (dwEventMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD))
677 *pfEvtsRecv |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
678 }
679 }
680
681 return rc;
682}
683
684
685RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort)
686{
687 PRTSERIALPORTINTERNAL pThis = hSerialPort;
688 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
689 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
690
691 if (!SetEvent(pThis->hEvtIntr))
692 return RTErrConvertFromWin32(GetLastError());
693
694 return VINF_SUCCESS;
695}
696
697
698RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet)
699{
700 PRTSERIALPORTINTERNAL pThis = hSerialPort;
701 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
702 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
703
704 BOOL fSucc = FALSE;
705 if (fSet)
706 fSucc = SetCommBreak(pThis->hDev);
707 else
708 fSucc = ClearCommBreak(pThis->hDev);
709
710 int rc = VINF_SUCCESS;
711 if (!fSucc)
712 rc = RTErrConvertFromWin32(GetLastError());
713
714 return rc;
715}
716
717
718RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet)
719{
720 PRTSERIALPORTINTERNAL pThis = hSerialPort;
721 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
722 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
723
724 BOOL fSucc = TRUE;
725 if (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR)
726 fSucc = EscapeCommFunction(pThis->hDev, SETDTR);
727 if ( fSucc
728 && (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS))
729 fSucc = EscapeCommFunction(pThis->hDev, SETRTS);
730
731 if ( fSucc
732 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR))
733 fSucc = EscapeCommFunction(pThis->hDev, CLRDTR);
734 if ( fSucc
735 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS))
736 fSucc = EscapeCommFunction(pThis->hDev, CLRRTS);
737
738 int rc = VINF_SUCCESS;
739 if (!fSucc)
740 rc = RTErrConvertFromWin32(GetLastError());
741
742 return rc;
743}
744
745
746RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines)
747{
748 PRTSERIALPORTINTERNAL pThis = hSerialPort;
749 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
750 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
751 AssertPtrReturn(pfStsLines, VERR_INVALID_POINTER);
752
753 *pfStsLines = 0;
754
755 int rc = VINF_SUCCESS;
756 DWORD fStsLinesQueried = 0;
757
758 /* Get the new state */
759 if (GetCommModemStatus(pThis->hDev, &fStsLinesQueried))
760 {
761 *pfStsLines |= (fStsLinesQueried & MS_RLSD_ON) ? RTSERIALPORT_STS_LINE_DCD : 0;
762 *pfStsLines |= (fStsLinesQueried & MS_RING_ON) ? RTSERIALPORT_STS_LINE_RI : 0;
763 *pfStsLines |= (fStsLinesQueried & MS_DSR_ON) ? RTSERIALPORT_STS_LINE_DSR : 0;
764 *pfStsLines |= (fStsLinesQueried & MS_CTS_ON) ? RTSERIALPORT_STS_LINE_CTS : 0;
765 }
766 else
767 rc = RTErrConvertFromWin32(GetLastError());
768
769 return rc;
770}
771
Note: See TracBrowser for help on using the repository browser.

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