VirtualBox

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

Last change on this file since 73630 was 73630, checked in by vboxsync, 6 years ago

Runtime/serialport-win.cpp: Fixes for RTSerialPortOpen()

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.6 KB
Line 
1/* $Id: serialport-win.cpp 73630 2018-08-13 10:39:39Z 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 {
270 rc = rtSerialPortSetDefaultCfg(pThis);
271 if (RT_SUCCESS(rc))
272 {
273 *phSerialPort = pThis;
274 return rc;
275 }
276 }
277 else
278 rc = RTErrConvertFromWin32(GetLastError());
279
280 CloseHandle(pThis->hEvtIntr);
281 }
282 else
283 rc = RTErrConvertFromWin32(GetLastError());
284
285 CloseHandle(pThis->hEvtDev);
286 }
287 else
288 rc = RTErrConvertFromWin32(GetLastError());
289
290 RTMemFree(pThis);
291 }
292 else
293 rc = VERR_NO_MEMORY;
294
295 return rc;
296}
297
298
299RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort)
300{
301 PRTSERIALPORTINTERNAL pThis = hSerialPort;
302 if (pThis == NIL_RTSERIALPORT)
303 return VINF_SUCCESS;
304 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
305 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
306
307 /*
308 * Do the cleanup.
309 */
310 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE);
311
312 if (pThis->fWritePending)
313 rtSerialPortWriteCheckCompletion(pThis);
314
315 CloseHandle(pThis->hDev);
316 CloseHandle(pThis->hEvtDev);
317 CloseHandle(pThis->hEvtIntr);
318 pThis->hDev = NULL;
319 pThis->hEvtDev = NULL;
320 pThis->hEvtIntr = NULL;
321 RTMemFree(pThis);
322 return VINF_SUCCESS;
323}
324
325
326RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort)
327{
328 PRTSERIALPORTINTERNAL pThis = hSerialPort;
329 AssertPtrReturn(pThis, -1);
330 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, -1);
331
332 return (RTHCINTPTR)pThis->hDev;
333}
334
335
336RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
337{
338 PRTSERIALPORTINTERNAL pThis = hSerialPort;
339 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
340 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
341 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
342 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
343
344 /*
345 * Kick of an overlapped read.
346 */
347 int rc = VINF_SUCCESS;
348 uint8_t *pbBuf = (uint8_t *)pvBuf;
349
350 while ( cbToRead > 0
351 && RT_SUCCESS(rc))
352 {
353 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
354 DWORD cbRead = 0;
355 if (ReadFile(pThis->hDev, pbBuf,
356 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
357 &cbRead, &pThis->Overlapped))
358 {
359 if (pcbRead)
360 {
361 *pcbRead = cbRead;
362 break;
363 }
364 rc = VINF_SUCCESS;
365 }
366 else if (GetLastError() == ERROR_IO_PENDING)
367 {
368 DWORD dwWait = WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
369 if (dwWait == WAIT_OBJECT_0)
370 {
371 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
372 {
373 if (pcbRead)
374 {
375 *pcbRead = cbRead;
376 break;
377 }
378 rc = VINF_SUCCESS;
379 }
380 else
381 rc = RTErrConvertFromWin32(GetLastError());
382 }
383 else
384 {
385 Assert(dwWait == WAIT_FAILED);
386 rc = RTErrConvertFromWin32(GetLastError());
387 }
388 }
389 else
390 rc = RTErrConvertFromWin32(GetLastError());
391
392 if (RT_SUCCESS(rc))
393 {
394 cbToRead -= cbRead;
395 pbBuf += cbRead;
396 }
397 }
398
399 return rc;
400}
401
402
403RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
404{
405 PRTSERIALPORTINTERNAL pThis = hSerialPort;
406 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
407 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
408 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
409 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
410 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
411
412 *pcbRead = 0;
413
414 /*
415 * Kick of an overlapped read. It should return immediately if
416 * there is bytes in the buffer. If not, we'll cancel it and see
417 * what we get back.
418 */
419 int rc = VINF_SUCCESS;
420 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
421 DWORD cbRead = 0;
422 if ( cbToRead == 0
423 || ReadFile(pThis->hDev, pvBuf,
424 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
425 &cbRead, &pThis->Overlapped))
426 {
427 *pcbRead = cbRead;
428 rc = VINF_SUCCESS;
429 }
430 else if (GetLastError() == ERROR_IO_PENDING)
431 {
432 if (!CancelIo(pThis->hDev))
433 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
434 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
435 {
436 *pcbRead = cbRead;
437 rc = VINF_SUCCESS;
438 }
439 else if (GetLastError() == ERROR_OPERATION_ABORTED)
440 {
441 *pcbRead = 0;
442 rc = VINF_TRY_AGAIN;
443 }
444 else
445 rc = RTErrConvertFromWin32(GetLastError());
446 }
447 else
448 rc = RTErrConvertFromWin32(GetLastError());
449
450 return rc;
451}
452
453
454RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
455{
456 PRTSERIALPORTINTERNAL pThis = hSerialPort;
457 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
458 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
459 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
460 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
461
462 /* If I/O is pending, check if it has completed. */
463 int rc = VINF_SUCCESS;
464 if (pThis->fWritePending)
465 rc = rtSerialPortWriteCheckCompletion(pThis);
466 if (rc == VINF_SUCCESS)
467 {
468 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
469
470 while ( cbToWrite > 0
471 && RT_SUCCESS(rc))
472 {
473 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
474 DWORD cbWritten = 0;
475 if (WriteFile(pThis->hDev, pbBuf,
476 cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0,
477 &cbWritten, &pThis->Overlapped))
478 {
479 if (pcbWritten)
480 {
481 *pcbWritten = cbWritten;
482 break;
483 }
484 rc = VINF_SUCCESS;
485 }
486 else if (GetLastError() == ERROR_IO_PENDING)
487 {
488 DWORD dwWait = WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
489 if (dwWait == WAIT_OBJECT_0)
490 {
491 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbWritten, TRUE /*fWait*/))
492 {
493 if (pcbWritten)
494 {
495 *pcbWritten = cbWritten;
496 break;
497 }
498 rc = VINF_SUCCESS;
499 }
500 else
501 rc = RTErrConvertFromWin32(GetLastError());
502 }
503 else
504 {
505 Assert(dwWait == WAIT_FAILED);
506 rc = RTErrConvertFromWin32(GetLastError());
507 }
508 }
509 else
510 rc = RTErrConvertFromWin32(GetLastError());
511
512 if (RT_SUCCESS(rc))
513 {
514 cbToWrite -= cbWritten;
515 pbBuf += cbWritten;
516 }
517 }
518 }
519
520 return rc;
521}
522
523
524RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
525{
526 PRTSERIALPORTINTERNAL pThis = hSerialPort;
527 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
528 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
529 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
530 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
531 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
532
533 /* If I/O is pending, check if it has completed. */
534 int rc = VINF_SUCCESS;
535 if (pThis->fWritePending)
536 rc = rtSerialPortWriteCheckCompletion(pThis);
537 if (rc == VINF_SUCCESS)
538 {
539 Assert(!pThis->fWritePending);
540
541 /* Do the bounce buffering. */
542 if ( pThis->cbBounceBufAlloc < cbToWrite
543 && pThis->cbBounceBufAlloc < RTSERIALPORT_NT_SIZE)
544 {
545 if (cbToWrite > RTSERIALPORT_NT_SIZE)
546 cbToWrite = RTSERIALPORT_NT_SIZE;
547 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K));
548 if (pv)
549 {
550 pThis->pbBounceBuf = (uint8_t *)pv;
551 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K);
552 }
553 else
554 rc = VERR_NO_MEMORY;
555 }
556 else if (cbToWrite > RTSERIALPORT_NT_SIZE)
557 cbToWrite = RTSERIALPORT_NT_SIZE;
558 if (RT_SUCCESS(rc) && cbToWrite)
559 {
560 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite);
561 pThis->cbBounceBufUsed = (uint32_t)cbToWrite;
562
563 /* Submit the write. */
564 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
565 DWORD cbWritten = 0;
566 if (WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
567 &cbWritten, &pThis->Overlapped))
568 {
569 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */
570 rc = VINF_SUCCESS;
571 }
572 else if (GetLastError() == ERROR_IO_PENDING)
573 {
574 *pcbWritten = cbToWrite;
575 pThis->fWritePending = true;
576 rc = VINF_SUCCESS;
577 }
578 else
579 rc = RTErrConvertFromWin32(GetLastError());
580 }
581 else if (RT_SUCCESS(rc))
582 *pcbWritten = 0;
583 }
584 else if (RT_SUCCESS(rc))
585 *pcbWritten = 0;
586
587 return rc;
588}
589
590
591RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg)
592{
593 PRTSERIALPORTINTERNAL pThis = hSerialPort;
594 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
595 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
596
597 pCfg->uBaudRate = pThis->PortCfg.BaudRate;
598 switch (pThis->PortCfg.Parity)
599 {
600 case NOPARITY:
601 pCfg->enmParity = RTSERIALPORTPARITY_NONE;
602 break;
603 case EVENPARITY:
604 pCfg->enmParity = RTSERIALPORTPARITY_EVEN;
605 break;
606 case ODDPARITY:
607 pCfg->enmParity = RTSERIALPORTPARITY_ODD;
608 break;
609 case MARKPARITY:
610 pCfg->enmParity = RTSERIALPORTPARITY_MARK;
611 break;
612 case SPACEPARITY:
613 pCfg->enmParity = RTSERIALPORTPARITY_SPACE;
614 break;
615 default:
616 AssertFailed();
617 return VERR_INTERNAL_ERROR;
618 }
619
620 switch (pThis->PortCfg.ByteSize)
621 {
622 case 5:
623 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
624 break;
625 case 6:
626 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
627 break;
628 case 7:
629 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
630 break;
631 case 8:
632 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
633 break;
634 default:
635 AssertFailed();
636 return VERR_INTERNAL_ERROR;
637 }
638
639 switch (pThis->PortCfg.StopBits)
640 {
641 case ONESTOPBIT:
642 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
643 break;
644 case ONE5STOPBITS:
645 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
646 break;
647 case TWOSTOPBITS:
648 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
649 break;
650 default:
651 AssertFailed();
652 return VERR_INTERNAL_ERROR;
653 }
654
655 return VINF_SUCCESS;
656}
657
658
659RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo)
660{
661 PRTSERIALPORTINTERNAL pThis = hSerialPort;
662 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
663 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
664
665 RT_NOREF(pErrInfo);
666
667 DCB DcbNew;
668 memcpy(&DcbNew, &pThis->PortCfg, sizeof(DcbNew));
669 DcbNew.BaudRate = pCfg->uBaudRate;
670
671 switch (pCfg->enmParity)
672 {
673 case RTSERIALPORTPARITY_NONE:
674 DcbNew.Parity = NOPARITY;
675 break;
676 case RTSERIALPORTPARITY_EVEN:
677 DcbNew.Parity = EVENPARITY;
678 break;
679 case RTSERIALPORTPARITY_ODD:
680 DcbNew.Parity = ODDPARITY;
681 break;
682 case RTSERIALPORTPARITY_MARK:
683 DcbNew.Parity = MARKPARITY;
684 break;
685 case RTSERIALPORTPARITY_SPACE:
686 DcbNew.Parity = SPACEPARITY;
687 break;
688 default:
689 AssertFailedReturn(VERR_INVALID_PARAMETER);
690 }
691
692 switch (pCfg->enmDataBitCount)
693 {
694 case RTSERIALPORTDATABITS_5BITS:
695 DcbNew.ByteSize = 5;
696 break;
697 case RTSERIALPORTDATABITS_6BITS:
698 DcbNew.ByteSize = 6;
699 break;
700 case RTSERIALPORTDATABITS_7BITS:
701 DcbNew.ByteSize = 7;
702 break;
703 case RTSERIALPORTDATABITS_8BITS:
704 DcbNew.ByteSize = 8;
705 break;
706 default:
707 AssertFailedReturn(VERR_INVALID_PARAMETER);
708 }
709
710 switch (pCfg->enmStopBitCount)
711 {
712 case RTSERIALPORTSTOPBITS_ONE:
713 DcbNew.StopBits = ONESTOPBIT;
714 break;
715 case RTSERIALPORTSTOPBITS_ONEPOINTFIVE:
716 AssertReturn(pCfg->enmDataBitCount == RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
717 DcbNew.StopBits = ONE5STOPBITS;
718 break;
719 case RTSERIALPORTSTOPBITS_TWO:
720 AssertReturn(pCfg->enmDataBitCount != RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
721 DcbNew.StopBits = TWOSTOPBITS;
722 break;
723 default:
724 AssertFailedReturn(VERR_INVALID_PARAMETER);
725 }
726
727 int rc = VINF_SUCCESS;
728 if (!SetCommState(pThis->hDev, &DcbNew))
729 rc = RTErrConvertFromWin32(GetLastError());
730 else
731 memcpy(&pThis->PortCfg, &DcbNew, sizeof(DcbNew));
732
733 return rc;
734}
735
736
737RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv,
738 RTMSINTERVAL msTimeout)
739{
740 PRTSERIALPORTINTERNAL pThis = hSerialPort;
741 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
742 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
743 AssertReturn(!(fEvtMask & ~RTSERIALPORT_EVT_F_VALID_MASK), VERR_INVALID_PARAMETER);
744 AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER);
745
746 *pfEvtsRecv = 0;
747
748 int rc = VINF_SUCCESS;
749 if (fEvtMask != pThis->fEvtMask)
750 rc = rtSerialPortWinUpdateEvtMask(pThis, fEvtMask);
751
752 if (RT_SUCCESS(rc))
753 {
754 DWORD dwEventMask = 0;
755 HANDLE ahWait[2];
756 ahWait[0] = pThis->hEvtDev;
757 ahWait[1] = pThis->hEvtIntr;
758
759 RT_ZERO(pThis->Overlapped);
760 pThis->Overlapped.hEvent = pThis->hEvtDev;
761
762 if (!WaitCommEvent(pThis->hDev, &dwEventMask, &pThis->Overlapped))
763 {
764 DWORD dwRet = GetLastError();
765 if (dwRet == ERROR_IO_PENDING)
766 {
767 dwRet = WaitForMultipleObjects(2, ahWait, FALSE, msTimeout == RT_INDEFINITE_WAIT ? INFINITE : msTimeout);
768 if (dwRet == WAIT_TIMEOUT)
769 rc = VERR_TIMEOUT;
770 else if (dwRet == WAIT_FAILED)
771 rc = RTErrConvertFromWin32(GetLastError());
772 else if (dwRet != WAIT_OBJECT_0)
773 rc = VERR_INTERRUPTED;
774 }
775 else
776 rc = RTErrConvertFromWin32(dwRet);
777 }
778
779 if (RT_SUCCESS(rc))
780 {
781 /* Check the event */
782 if (dwEventMask & EV_RXCHAR)
783 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_RX;
784 if (dwEventMask & EV_TXEMPTY)
785 {
786 if (pThis->fWritePending)
787 {
788 rc = rtSerialPortWriteCheckCompletion(pThis);
789 if (rc == VINF_SUCCESS)
790 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
791 else
792 rc = VINF_SUCCESS;
793 }
794 else
795 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
796 }
797 if (dwEventMask & EV_BREAK)
798 *pfEvtsRecv |= RTSERIALPORT_EVT_F_BREAK_DETECTED;
799 if (dwEventMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD))
800 *pfEvtsRecv |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
801 }
802 }
803
804 return rc;
805}
806
807
808RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort)
809{
810 PRTSERIALPORTINTERNAL pThis = hSerialPort;
811 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
812 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
813
814 if (!SetEvent(pThis->hEvtIntr))
815 return RTErrConvertFromWin32(GetLastError());
816
817 return VINF_SUCCESS;
818}
819
820
821RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet)
822{
823 PRTSERIALPORTINTERNAL pThis = hSerialPort;
824 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
825 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
826
827 BOOL fSucc = FALSE;
828 if (fSet)
829 fSucc = SetCommBreak(pThis->hDev);
830 else
831 fSucc = ClearCommBreak(pThis->hDev);
832
833 int rc = VINF_SUCCESS;
834 if (!fSucc)
835 rc = RTErrConvertFromWin32(GetLastError());
836
837 return rc;
838}
839
840
841RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet)
842{
843 PRTSERIALPORTINTERNAL pThis = hSerialPort;
844 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
845 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
846
847 BOOL fSucc = TRUE;
848 if (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR)
849 fSucc = EscapeCommFunction(pThis->hDev, SETDTR);
850 if ( fSucc
851 && (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS))
852 fSucc = EscapeCommFunction(pThis->hDev, SETRTS);
853
854 if ( fSucc
855 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR))
856 fSucc = EscapeCommFunction(pThis->hDev, CLRDTR);
857 if ( fSucc
858 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS))
859 fSucc = EscapeCommFunction(pThis->hDev, CLRRTS);
860
861 int rc = VINF_SUCCESS;
862 if (!fSucc)
863 rc = RTErrConvertFromWin32(GetLastError());
864
865 return rc;
866}
867
868
869RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines)
870{
871 PRTSERIALPORTINTERNAL pThis = hSerialPort;
872 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
873 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
874 AssertPtrReturn(pfStsLines, VERR_INVALID_POINTER);
875
876 *pfStsLines = 0;
877
878 int rc = VINF_SUCCESS;
879 DWORD fStsLinesQueried = 0;
880
881 /* Get the new state */
882 if (GetCommModemStatus(pThis->hDev, &fStsLinesQueried))
883 {
884 *pfStsLines |= (fStsLinesQueried & MS_RLSD_ON) ? RTSERIALPORT_STS_LINE_DCD : 0;
885 *pfStsLines |= (fStsLinesQueried & MS_RING_ON) ? RTSERIALPORT_STS_LINE_RI : 0;
886 *pfStsLines |= (fStsLinesQueried & MS_DSR_ON) ? RTSERIALPORT_STS_LINE_DSR : 0;
887 *pfStsLines |= (fStsLinesQueried & MS_CTS_ON) ? RTSERIALPORT_STS_LINE_CTS : 0;
888 }
889 else
890 rc = RTErrConvertFromWin32(GetLastError());
891
892 return rc;
893}
894
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