VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/os2/serialport-os2.cpp@ 106580

Last change on this file since 106580 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.6 KB
Line 
1/* $Id: serialport-os2.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Serial Port API, OS/2 Implementation.
4 */
5
6/*
7 * Copyright (C) 2017-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define INCL_BASE
42#define INCL_DOSFILEMGR
43#define INCL_ERRORS
44#define INCL_DOS
45#define INCL_DOSDEVIOCTL
46#define INCL_DOSDEVICES
47#include <os2.h>
48#undef RT_MAX
49
50#include <iprt/serialport.h>
51#include "internal/iprt.h"
52
53#include <iprt/asm.h>
54#include <iprt/assert.h>
55#include <iprt/cdefs.h>
56#include <iprt/err.h>
57#include <iprt/mem.h>
58#include <iprt/string.h>
59#include <iprt/time.h>
60#include "internal/magics.h"
61
62
63
64/*********************************************************************************************************************************
65* Structures and Typedefs *
66*********************************************************************************************************************************/
67
68/**
69 * Returned data structure for ASYNC_EXTGETBAUDRATE.
70 */
71typedef struct OS2EXTGETBAUDRATEDATA
72{
73 /** Current bit rate. */
74 ULONG uBitRateCur;
75 /** Fraction of the current bit rate. */
76 BYTE bBitRateCurFrac;
77 /** Minimum supported bit rate. */
78 ULONG uBitRateMin;
79 /** Fraction of the minimum bit rate. */
80 BYTE bBitRateCurMin;
81 /** Maximum supported bit rate. */
82 ULONG uBitRateMax;
83 /** Fraction of the maximum bit rate. */
84 BYTE bBitRateCurMax;
85} OS2EXTGETBAUDRATEDATA;
86/** Pointer to the get extended baud rate data packet. */
87typedef OS2EXTGETBAUDRATEDATA *POS2EXTGETBAUDRATEDATA;
88
89
90/**
91 * Data packet for the ASYNC_EXTSETBAUDRATE ioctl.
92 */
93typedef struct OS2EXTSETBAUDRATEDATA
94{
95 /** Current bit rate. */
96 ULONG uBitRate;
97 /** Fraction of the current bit rate. */
98 BYTE bBitRateFrac;
99} OS2EXTSETBAUDRATEDATA;
100/** Pointer to the set extended baud rate data packet. */
101typedef OS2EXTSETBAUDRATEDATA *POS2EXTSETBAUDRATEDATA;
102
103
104/**
105 * Data packet for the ASYNC_GETLINECTRL ioctl.
106 */
107typedef struct OS2GETLINECTRLDATA
108{
109 /** Returns the current amount of data bits in a symbol used for the communication. */
110 BYTE bDataBits;
111 /** Current parity setting. */
112 BYTE bParity;
113 /** Current number of stop bits. */
114 BYTE bStopBits;
115 /** Flag whether a break condition is currently transmitted on the line. */
116 BYTE bTxBrk;
117} OS2GETLINECTRLDATA;
118/** Pointer to the get line control data packet. */
119typedef OS2GETLINECTRLDATA *POS2GETLINECTRLDATA;
120
121
122/**
123 * Data packet for the ASYNC_SETLINECTRL ioctl.
124 */
125typedef struct OS2SETLINECTRLDATA
126{
127 /** Returns the current amount of data bits in a symbol used for the communication. */
128 BYTE bDataBits;
129 /** Current parity setting. */
130 BYTE bParity;
131 /** Current number of stop bits. */
132 BYTE bStopBits;
133} OS2SETLINECTRLDATA;
134/** Pointer to the get line control data packet. */
135typedef OS2SETLINECTRLDATA *POS2SETLINECTRLDATA;
136
137
138/**
139 * Internal serial port state.
140 */
141typedef struct RTSERIALPORTINTERNAL
142{
143 /** Magic value (RTSERIALPORT_MAGIC). */
144 uint32_t u32Magic;
145 /** Flags given while opening the serial port. */
146 uint32_t fOpenFlags;
147 /** The file descriptor of the serial port. */
148 HFILE hDev;
149 /** Flag whether blocking mode is currently enabled. */
150 bool fBlocking;
151 /** Flag whether RTSerialPortEvtPoll() was interrupted by RTSerialPortEvtPollInterrupt(). */
152 volatile bool fInterrupt;
153} RTSERIALPORTINTERNAL;
154/** Pointer to the internal serial port state. */
155typedef RTSERIALPORTINTERNAL *PRTSERIALPORTINTERNAL;
156
157
158
159/*********************************************************************************************************************************
160* Defined Constants And Macros *
161*********************************************************************************************************************************/
162
163/** Indicator whether the CTS input is set/clear. */
164#define OS2_GET_MODEM_INPUT_CTS RT_BIT(4)
165/** Indicator whether the DSR input is set/clear. */
166#define OS2_GET_MODEM_INPUT_DSR RT_BIT(5)
167/** Indicator whether the RI input is set/clear. */
168#define OS2_GET_MODEM_INPUT_RI RT_BIT(6)
169/** Indicator whether the DCD input is set/clear. */
170#define OS2_GET_MODEM_INPUT_DCD RT_BIT(7)
171
172/** There is something to read on the serial port. */
173#define OS2_GET_COMM_EVT_RX RT_BIT(0)
174/** A receive timeout interrupt was generated on the serial port during a read request. */
175#define OS2_GET_COMM_EVT_RTI RT_BIT(1)
176/** The transmit queue for the serial port is empty. */
177#define OS2_GET_COMM_EVT_TX_EMPTY RT_BIT(2)
178/** The CTS signal changes state. */
179#define OS2_GET_COMM_EVT_CTS_CHG RT_BIT(3)
180/** The DSR signal changes state. */
181#define OS2_GET_COMM_EVT_DSR_CHG RT_BIT(4)
182/** The DCD signal changes state. */
183#define OS2_GET_COMM_EVT_DCD_CHG RT_BIT(5)
184/** A break condition was detected on the serial port. */
185#define OS2_GET_COMM_EVT_BRK RT_BIT(6)
186/** A parity, framing or receive hardware overrun error occurred. */
187#define OS2_GET_COMM_EVT_COMM_ERR RT_BIT(7)
188/** Trailing edge ring indicator was detected. */
189#define OS2_GET_COMM_EVT_RI_TRAIL_EDGE RT_BIT(8)
190
191
192/*********************************************************************************************************************************
193* Global variables *
194*********************************************************************************************************************************/
195/** OS/2 parity value to IPRT parity enum. */
196static RTSERIALPORTPARITY s_aParityConvTbl[] =
197{
198 RTSERIALPORTPARITY_NONE,
199 RTSERIALPORTPARITY_ODD,
200 RTSERIALPORTPARITY_EVEN,
201 RTSERIALPORTPARITY_MARK,
202 RTSERIALPORTPARITY_SPACE
203};
204
205/** OS/2 data bits value to IPRT data bits enum. */
206static RTSERIALPORTDATABITS s_aDataBitsConvTbl[] =
207{
208 RTSERIALPORTDATABITS_INVALID,
209 RTSERIALPORTDATABITS_INVALID,
210 RTSERIALPORTDATABITS_INVALID,
211 RTSERIALPORTDATABITS_INVALID,
212 RTSERIALPORTDATABITS_INVALID,
213 RTSERIALPORTDATABITS_5BITS,
214 RTSERIALPORTDATABITS_6BITS,
215 RTSERIALPORTDATABITS_7BITS,
216 RTSERIALPORTDATABITS_8BITS
217};
218
219/** OS/2 stop bits value to IPRT stop bits enum. */
220static RTSERIALPORTSTOPBITS s_aStopBitsConvTbl[] =
221{
222 RTSERIALPORTSTOPBITS_ONE,
223 RTSERIALPORTSTOPBITS_ONEPOINTFIVE,
224 RTSERIALPORTSTOPBITS_TWO
225};
226
227
228/*********************************************************************************************************************************
229* Internal Functions *
230*********************************************************************************************************************************/
231
232/**
233 * The slow path of rtSerialPortSwitchBlockingMode that does the actual switching.
234 *
235 * @returns IPRT status code.
236 * @param pThis The internal serial port instance data.
237 * @param fBlocking The desired mode of operation.
238 * @remarks Do not call directly.
239 *
240 * @note Affects only read behavior.
241 */
242static int rtSerialPortSwitchBlockingModeSlow(PRTSERIALPORTINTERNAL pThis, bool fBlocking)
243{
244 DCBINFO DcbInfo;
245 ULONG cbDcbInfo = sizeof(DcbInfo);
246 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &DcbInfo, cbDcbInfo, &cbDcbInfo);
247 if (!rcOs2)
248 {
249 DcbInfo.fbTimeout &= ~0x06;
250 DcbInfo.fbTimeout |= fBlocking ? 0x04 : 0x06;
251 rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_SETDCBINFO, &DcbInfo, cbDcbInfo, &cbDcbInfo, NULL, 0, NULL);
252 if (rcOs2)
253 return RTErrConvertFromOS2(rcOs2);
254 }
255 else
256 return RTErrConvertFromOS2(rcOs2);
257
258 pThis->fBlocking = fBlocking;
259 return VINF_SUCCESS;
260}
261
262
263/**
264 * Switches the serial port to the desired blocking mode if necessary.
265 *
266 * @returns IPRT status code.
267 * @param pThis The internal serial port instance data.
268 * @param fBlocking The desired mode of operation.
269 *
270 * @note Affects only read behavior.
271 */
272DECLINLINE(int) rtSerialPortSwitchBlockingMode(PRTSERIALPORTINTERNAL pThis, bool fBlocking)
273{
274 if (pThis->fBlocking != fBlocking)
275 return rtSerialPortSwitchBlockingModeSlow(pThis, fBlocking);
276 return VINF_SUCCESS;
277}
278
279
280RTDECL(int) RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags)
281{
282 AssertPtrReturn(phSerialPort, VERR_INVALID_POINTER);
283 AssertPtrReturn(pszPortAddress, VERR_INVALID_POINTER);
284 AssertReturn(*pszPortAddress != '\0', VERR_INVALID_PARAMETER);
285 AssertReturn(!(fFlags & ~RTSERIALPORT_OPEN_F_VALID_MASK), VERR_INVALID_PARAMETER);
286 AssertReturn((fFlags & RTSERIALPORT_OPEN_F_READ) || (fFlags & RTSERIALPORT_OPEN_F_WRITE),
287 VERR_INVALID_PARAMETER);
288
289 int rc = VINF_SUCCESS;
290 PRTSERIALPORTINTERNAL pThis = (PRTSERIALPORTINTERNAL)RTMemAllocZ(sizeof(*pThis));
291 if (pThis)
292 {
293 ULONG fOpenMode = OPEN_SHARE_DENYREADWRITE
294 | OPEN_FLAGS_SEQUENTIAL
295 | OPEN_FLAGS_NOINHERIT
296 | OPEN_FLAGS_FAIL_ON_ERROR;
297
298 if ((fFlags & RTSERIALPORT_OPEN_F_READ) && !(fFlags & RTSERIALPORT_OPEN_F_WRITE))
299 fOpenMode |= OPEN_ACCESS_READONLY;
300 else if (!(fFlags & RTSERIALPORT_OPEN_F_READ) && (fFlags & RTSERIALPORT_OPEN_F_WRITE))
301 fOpenMode |= OPEN_ACCESS_WRITEONLY;
302 else
303 fOpenMode |= OPEN_ACCESS_READWRITE;
304
305 pThis->u32Magic = RTSERIALPORT_MAGIC;
306 pThis->fOpenFlags = fFlags;
307 pThis->fInterrupt = false;
308 pThis->fBlocking = true;
309
310 ULONG uAction = 0;
311 ULONG rcOs2 = DosOpen((const UCHAR *)pszPortAddress, &pThis->hDev, &uAction, 0, FILE_NORMAL, FILE_OPEN, fOpenMode, NULL);
312 if (!rcOs2)
313 {
314 /* Switch to a known read blocking mode. */
315 rc = rtSerialPortSwitchBlockingMode(pThis, false);
316 if (RT_SUCCESS(rc))
317 {
318 *phSerialPort = pThis;
319 return VINF_SUCCESS;
320 }
321
322 DosClose(pThis->hDev);
323 }
324 else
325 rc = RTErrConvertFromOS2(rcOs2);
326
327 RTMemFree(pThis);
328 }
329 else
330 rc = VERR_NO_MEMORY;
331
332 return rc;
333}
334
335
336RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort)
337{
338 PRTSERIALPORTINTERNAL pThis = hSerialPort;
339 if (pThis == NIL_RTSERIALPORT)
340 return VINF_SUCCESS;
341 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
342 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
343
344 /*
345 * Do the cleanup.
346 */
347 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE);
348
349 DosClose(pThis->hDev);
350 RTMemFree(pThis);
351 return VINF_SUCCESS;
352}
353
354
355RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort)
356{
357 PRTSERIALPORTINTERNAL pThis = hSerialPort;
358 AssertPtrReturn(pThis, -1);
359 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, -1);
360
361 return pThis->hDev;
362}
363
364
365RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
366{
367 PRTSERIALPORTINTERNAL pThis = hSerialPort;
368 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
369 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
370 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
371 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
372
373 int rc = rtSerialPortSwitchBlockingMode(pThis, true);
374 if (RT_SUCCESS(rc))
375 {
376 /*
377 * Attempt read.
378 */
379 ULONG cbRead = 0;
380 ULONG rcOs2 = DosRead(pThis->hDev, pvBuf, cbToRead, &cbRead);
381 if (!rcOs2)
382 {
383 if (pcbRead)
384 /* caller can handle partial read. */
385 *pcbRead = cbRead;
386 else
387 {
388 /* Caller expects all to be read. */
389 while (cbToRead > cbRead)
390 {
391 ULONG cbReadPart = 0;
392 rcOs2 = DosRead(pThis->hDev, (uint8_t *)pvBuf + cbRead, cbToRead - cbRead, &cbReadPart);
393 if (rcOs2)
394 return RTErrConvertFromOS2(rcOs2);
395
396 cbRead += cbReadPart;
397 }
398 }
399 }
400 else
401 rc = RTErrConvertFromOS2(rcOs2);
402 }
403
404 return rc;
405}
406
407
408RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
409{
410 PRTSERIALPORTINTERNAL pThis = hSerialPort;
411 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
412 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
413 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
414 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
415 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
416
417 *pcbRead = 0;
418
419 int rc = rtSerialPortSwitchBlockingMode(pThis, false);
420 if (RT_SUCCESS(rc))
421 {
422 ULONG cbThisRead = 0;
423 ULONG rcOs2 = DosRead(pThis->hDev, pvBuf, cbToRead, &cbThisRead);
424 if (!rcOs2)
425 {
426 *pcbRead = cbThisRead;
427
428 if (cbThisRead == 0)
429 rc = VINF_TRY_AGAIN;
430 }
431 else
432 rc = RTErrConvertFromOS2(rcOs2);
433 }
434
435 return rc;
436}
437
438
439RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
440{
441 PRTSERIALPORTINTERNAL pThis = hSerialPort;
442 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
443 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
444 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
445 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
446
447 /*
448 * Attempt write.
449 */
450 int rc = VINF_SUCCESS;
451 ULONG cbThisWritten = 0;
452 ULONG rcOs2 = DosWrite(pThis->hDev, pvBuf, cbToWrite, &cbThisWritten);
453 if (!rcOs2)
454 {
455 if (pcbWritten)
456 /* caller can handle partial write. */
457 *pcbWritten = cbThisWritten;
458 else
459 {
460 /** @todo Wait for TX empty and loop. */
461 rc = VERR_NOT_SUPPORTED;
462 }
463 }
464 else
465 rc = RTErrConvertFromOS2(rcOs2);
466
467 return rc;
468}
469
470
471RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
472{
473 PRTSERIALPORTINTERNAL pThis = hSerialPort;
474 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
475 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
476 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
477 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
478 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
479
480 *pcbWritten = 0;
481
482 int rc = VINF_SUCCESS;
483 ULONG cbThisWritten = 0;
484 ULONG rcOs2 = DosWrite(pThis->hDev, pvBuf, cbToWrite, &cbThisWritten);
485 if (!rcOs2)
486 {
487 *pcbWritten = cbThisWritten;
488 if (!cbThisWritten)
489 rc = VINF_TRY_AGAIN;
490 }
491 else
492 rc = RTErrConvertFromOS2(rcOs2);
493
494 return rc;
495}
496
497
498RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg)
499{
500 PRTSERIALPORTINTERNAL pThis = hSerialPort;
501 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
502 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
503
504 int rc = VINF_SUCCESS;
505 OS2EXTGETBAUDRATEDATA ExtBaudRate;
506 ULONG cbExtBaudRate = sizeof(ExtBaudRate);
507 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_EXTGETBAUDRATE, NULL, 0, NULL, &ExtBaudRate, cbExtBaudRate, &cbExtBaudRate);
508 if (!rcOs2)
509 {
510 OS2GETLINECTRLDATA LineCtrl;
511 ULONG cbLineCtrl = sizeof(LineCtrl);
512 rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_GETLINECTRL, NULL, 0, NULL, &LineCtrl, cbLineCtrl, &cbLineCtrl);
513 if (!rcOs2)
514 {
515 pCfg->uBaudRate = ExtBaudRate.uBitRateCur;
516 if (LineCtrl.bParity < RT_ELEMENTS(s_aParityConvTbl))
517 pCfg->enmParity = s_aParityConvTbl[LineCtrl.bParity];
518 else
519 rc = VERR_IPE_UNEXPECTED_STATUS;
520
521 if ( RT_SUCCESS(rc)
522 && LineCtrl.bDataBits < RT_ELEMENTS(s_aDataBitsConvTbl)
523 && s_aDataBitsConvTbl[LineCtrl.bDataBits] != RTSERIALPORTDATABITS_INVALID)
524 pCfg->enmDataBitCount = s_aDataBitsConvTbl[LineCtrl.bDataBits];
525 else
526 rc = VERR_IPE_UNEXPECTED_STATUS;
527
528 if ( RT_SUCCESS(rc)
529 && LineCtrl.bStopBits < RT_ELEMENTS(s_aStopBitsConvTbl))
530 pCfg->enmStopBitCount = s_aStopBitsConvTbl[LineCtrl.bStopBits];
531 else
532 rc = VERR_IPE_UNEXPECTED_STATUS;
533 }
534 else
535 rc = RTErrConvertFromOS2(rcOs2);
536 }
537 else
538 rc = RTErrConvertFromOS2(rcOs2);
539
540 return rc;
541}
542
543
544RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo)
545{
546 PRTSERIALPORTINTERNAL pThis = hSerialPort;
547 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
548 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
549
550 int rc = VINF_SUCCESS;
551 OS2EXTSETBAUDRATEDATA ExtBaudRate;
552 OS2SETLINECTRLDATA LineCtrl;
553 ULONG cbExtBaudRate = sizeof(ExtBaudRate);
554 ULONG cbLineCtrl = sizeof(LineCtrl);
555
556 ExtBaudRate.uBitRate = pCfg->uBaudRate;
557 ExtBaudRate.bBitRateFrac = 0;
558
559 BYTE idx = 0;
560 while (idx < RT_ELEMENTS(s_aParityConvTbl))
561 {
562 if (s_aParityConvTbl[idx] == pCfg->enmParity)
563 {
564 LineCtrl.bParity = idx;
565 break;
566 }
567 idx++;
568 }
569 AssertReturn(idx < RT_ELEMENTS(s_aParityConvTbl), VERR_INTERNAL_ERROR);
570
571 idx = 0;
572 while (idx < RT_ELEMENTS(s_aDataBitsConvTbl))
573 {
574 if (s_aDataBitsConvTbl[idx] == pCfg->enmDataBitCount)
575 {
576 LineCtrl.bDataBits = idx;
577 break;
578 }
579 idx++;
580 }
581 AssertReturn(idx < RT_ELEMENTS(s_aDataBitsConvTbl), VERR_INTERNAL_ERROR);
582
583 idx = 0;
584 while (idx < RT_ELEMENTS(s_aStopBitsConvTbl))
585 {
586 if (s_aStopBitsConvTbl[idx] == pCfg->enmStopBitCount)
587 {
588 LineCtrl.bStopBits = idx;
589 break;
590 }
591 idx++;
592 }
593 AssertReturn(idx < RT_ELEMENTS(s_aStopBitsConvTbl), VERR_INTERNAL_ERROR);
594
595 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE, &ExtBaudRate, cbExtBaudRate, &cbExtBaudRate, NULL, 0, NULL);
596 if (!rcOs2)
597 {
598 rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_SETLINECTRL, &LineCtrl, cbLineCtrl, &cbLineCtrl, NULL, 0, NULL);
599 if (rcOs2)
600 rc = RTErrConvertFromOS2(rcOs2);
601 }
602 else
603 rc = RTErrConvertFromOS2(rcOs2);
604
605 return rc;
606}
607
608
609RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv,
610 RTMSINTERVAL msTimeout)
611{
612 PRTSERIALPORTINTERNAL pThis = hSerialPort;
613 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
614 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
615 AssertReturn(!(fEvtMask & ~RTSERIALPORT_EVT_F_VALID_MASK), VERR_INVALID_PARAMETER);
616 AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER);
617
618 *pfEvtsRecv = 0;
619
620 /*
621 * We need to kind of busy wait here as there is, to my knowledge, no API
622 * to wait for a COM event.
623 *
624 * @todo Adaptive waiting
625 * @todo Handle rollover after 48days eventually
626 */
627 int rc = VINF_SUCCESS;
628 uint64_t tsStart = RTTimeSystemMilliTS();
629 do
630 {
631 if (ASMAtomicXchgBool(&pThis->fInterrupt, false))
632 {
633 rc = VERR_INTERRUPTED;
634 break;
635 }
636
637 USHORT fCommEvt = 0;
638 ULONG cbCommEvt = sizeof(fCommEvt);
639 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, NULL, 0, NULL,
640 &fCommEvt, cbCommEvt, &cbCommEvt);
641 if (!rcOs2)
642 {
643 AssertReturn(cbCommEvt = sizeof(fCommEvt), VERR_IPE_UNEXPECTED_STATUS);
644
645 if ( (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX)
646 && (fCommEvt & OS2_GET_COMM_EVT_RX))
647 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_RX;
648
649 /** @todo Is there something better to indicate that there is room in the queue instead of queue is empty? */
650 if ( (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX)
651 && (fCommEvt & OS2_GET_COMM_EVT_TX_EMPTY))
652 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
653
654 if ( (fEvtMask & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
655 && (fCommEvt & (OS2_GET_COMM_EVT_CTS_CHG | OS2_GET_COMM_EVT_DSR_CHG | OS2_GET_COMM_EVT_DCD_CHG)))
656 *pfEvtsRecv |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
657
658 if ( (fEvtMask & RTSERIALPORT_EVT_F_BREAK_DETECTED)
659 && (fCommEvt & OS2_GET_COMM_EVT_BRK))
660 *pfEvtsRecv |= RTSERIALPORT_EVT_F_BREAK_DETECTED;
661
662 if (*pfEvtsRecv != 0)
663 break;
664 }
665 else
666 {
667 rc = RTErrConvertFromOS2(rcOs2);
668 break;
669 }
670
671 uint64_t tsNow = RTTimeSystemMilliTS();
672 if ( msTimeout == RT_INDEFINITE_WAIT
673 || tsNow - tsStart < msTimeout)
674 DosSleep(1);
675 else
676 rc = VERR_TIMEOUT;
677 } while (RT_SUCCESS(rc));
678
679 return rc;
680}
681
682
683RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort)
684{
685 PRTSERIALPORTINTERNAL pThis = hSerialPort;
686 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
687 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
688
689 ASMAtomicXchgBool(&pThis->fInterrupt, true);
690 return VINF_SUCCESS;
691}
692
693
694RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet)
695{
696 PRTSERIALPORTINTERNAL pThis = hSerialPort;
697 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
698 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
699
700 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, fSet ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF,
701 NULL, 0, NULL, NULL, 0, NULL);
702
703 return RTErrConvertFromOS2(rcOs2);
704}
705
706
707RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet)
708{
709 PRTSERIALPORTINTERNAL pThis = hSerialPort;
710 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
711 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
712
713 MODEMSTATUS MdmSts;
714 ULONG cbMdmSts = sizeof(MdmSts);
715
716 MdmSts.fbModemOn = (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS ? 0x02 : 0x00)
717 | (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR ? 0x01 : 0x00);
718 MdmSts.fbModemOff = 0xff;
719 MdmSts.fbModemOff &= ~( (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS ? 0x02 : 0x00)
720 | (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR ? 0x01 : 0x00));
721
722 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, &MdmSts, cbMdmSts, &cbMdmSts, NULL, 0, NULL);
723
724 return RTErrConvertFromOS2(rcOs2);
725}
726
727
728RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines)
729{
730 PRTSERIALPORTINTERNAL pThis = hSerialPort;
731 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
732 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
733 AssertPtrReturn(pfStsLines, VERR_INVALID_POINTER);
734
735 *pfStsLines = 0;
736
737 int rc = VINF_SUCCESS;
738 BYTE fStsLines = 0;
739 ULONG cbStsLines = sizeof(fStsLines);
740 ULONG rcOs2 = DosDevIOCtl(pThis->hDev, IOCTL_ASYNC, ASYNC_GETMODEMINPUT, NULL, 0, NULL, &fStsLines, cbStsLines, &cbStsLines);
741 if (!rcOs2)
742 {
743 AssertReturn(cbStsLines == sizeof(BYTE), VERR_IPE_UNEXPECTED_STATUS);
744
745 *pfStsLines |= (fStsLines & OS2_GET_MODEM_INPUT_DCD) ? RTSERIALPORT_STS_LINE_DCD : 0;
746 *pfStsLines |= (fStsLines & OS2_GET_MODEM_INPUT_RI) ? RTSERIALPORT_STS_LINE_RI : 0;
747 *pfStsLines |= (fStsLines & OS2_GET_MODEM_INPUT_DSR) ? RTSERIALPORT_STS_LINE_DSR : 0;
748 *pfStsLines |= (fStsLines & OS2_GET_MODEM_INPUT_CTS) ? RTSERIALPORT_STS_LINE_CTS : 0;
749 }
750 else
751 rc = RTErrConvertFromOS2(rcOs2);
752
753 return rc;
754}
755
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