VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DrvHostSerialNew.cpp@ 73045

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

DevSerialNew,DrvHostSerialNew: Some bugfixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.9 KB
Line 
1/* $Id: DrvHostSerialNew.cpp 72132 2018-05-06 19:40:10Z vboxsync $ */
2/** @file
3 * VBox serial devices: Host serial driver
4 */
5
6/*
7 * Copyright (C) 2006-2018 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
18
19
20/*********************************************************************************************************************************
21* Header Files *
22*********************************************************************************************************************************/
23#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
24#include <VBox/vmm/pdm.h>
25#include <VBox/vmm/pdmserialifs.h>
26#include <VBox/err.h>
27
28#include <VBox/log.h>
29#include <iprt/asm.h>
30#include <iprt/assert.h>
31#include <iprt/file.h>
32#include <iprt/mem.h>
33#include <iprt/pipe.h>
34#include <iprt/semaphore.h>
35#include <iprt/uuid.h>
36#include <iprt/serialport.h>
37
38#include "VBoxDD.h"
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44
45/**
46 * Char driver instance data.
47 *
48 * @implements PDMISERIALCONNECTOR
49 */
50typedef struct DRVHOSTSERIAL
51{
52 /** Pointer to the driver instance structure. */
53 PPDMDRVINS pDrvIns;
54 /** Pointer to the serial port interface of the driver/device above us. */
55 PPDMISERIALPORT pDrvSerialPort;
56 /** Our serial interface. */
57 PDMISERIALCONNECTOR ISerialConnector;
58 /** I/O thread. */
59 PPDMTHREAD pIoThrd;
60 /** The serial port handle. */
61 RTSERIALPORT hSerialPort;
62 /** the device path */
63 char *pszDevicePath;
64
65 /** Amount of data available for sending from the device/driver above. */
66 volatile size_t cbAvailWr;
67 /** Small send buffer. */
68 uint8_t abTxBuf[16];
69 /** Amount of data in the buffer. */
70 size_t cbTxUsed;
71
72 /** The read queue. */
73 uint8_t abReadBuf[256];
74 /** Current offset to write to next. */
75 volatile uint32_t offWrite;
76 /** Current offset into the read buffer. */
77 volatile uint32_t offRead;
78 /** Current amount of data in the buffer. */
79 volatile size_t cbReadBuf;
80
81 /** Read/write statistics */
82 STAMCOUNTER StatBytesRead;
83 STAMCOUNTER StatBytesWritten;
84} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
85
86
87/*********************************************************************************************************************************
88* Global Variables *
89*********************************************************************************************************************************/
90
91
92/*********************************************************************************************************************************
93* Internal Functions *
94*********************************************************************************************************************************/
95
96
97/**
98 * Returns number of bytes free in the read buffer and pointer to the start of the free space
99 * in the read buffer.
100 *
101 * @returns Number of bytes free in the buffer.
102 * @param pThis The host serial driver instance.
103 * @param ppv Where to return the pointer if there is still free space.
104 */
105DECLINLINE(size_t) drvHostSerialReadBufGetWrite(PDRVHOSTSERIAL pThis, void **ppv)
106{
107 if (ppv)
108 *ppv = &pThis->abReadBuf[pThis->offWrite];
109
110 size_t cbFree = sizeof(pThis->abReadBuf) - ASMAtomicReadZ(&pThis->cbReadBuf);
111 if (cbFree)
112 cbFree = RT_MIN(cbFree, sizeof(pThis->abReadBuf) - pThis->offWrite);
113
114 return cbFree;
115}
116
117
118/**
119 * Returns number of bytes used in the read buffer and pointer to the next byte to read.
120 *
121 * @returns Number of bytes free in the buffer.
122 * @param pThis The host serial driver instance.
123 * @param ppv Where to return the pointer to the next data to read.
124 */
125DECLINLINE(size_t) drvHostSerialReadBufGetRead(PDRVHOSTSERIAL pThis, void **ppv)
126{
127 if (ppv)
128 *ppv = &pThis->abReadBuf[pThis->offRead];
129
130 size_t cbUsed = ASMAtomicReadZ(&pThis->cbReadBuf);
131 if (cbUsed)
132 cbUsed = RT_MIN(cbUsed, sizeof(pThis->abReadBuf) - pThis->offRead);
133
134 return cbUsed;
135}
136
137
138/**
139 * Advances the write position of the read buffer by the given amount of bytes.
140 *
141 * @returns nothing.
142 * @param pThis The host serial driver instance.
143 * @param cbAdv Number of bytes to advance.
144 */
145DECLINLINE(void) drvHostSerialReadBufWriteAdv(PDRVHOSTSERIAL pThis, size_t cbAdv)
146{
147 uint32_t offWrite = ASMAtomicReadU32(&pThis->offWrite);
148 offWrite = (offWrite + cbAdv) % sizeof(pThis->abReadBuf);
149 ASMAtomicWriteU32(&pThis->offWrite, offWrite);
150 ASMAtomicAddZ(&pThis->cbReadBuf, cbAdv);
151}
152
153
154/**
155 * Advances the read position of the read buffer by the given amount of bytes.
156 *
157 * @returns nothing.
158 * @param pThis The host serial driver instance.
159 * @param cbAdv Number of bytes to advance.
160 */
161DECLINLINE(void) drvHostSerialReadBufReadAdv(PDRVHOSTSERIAL pThis, size_t cbAdv)
162{
163 uint32_t offRead = ASMAtomicReadU32(&pThis->offRead);
164 offRead = (offRead + cbAdv) % sizeof(pThis->abReadBuf);
165 ASMAtomicWriteU32(&pThis->offRead, offRead);
166 ASMAtomicSubZ(&pThis->cbReadBuf, cbAdv);
167}
168
169
170/* -=-=-=-=- IBase -=-=-=-=- */
171
172/**
173 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
174 */
175static DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
176{
177 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
178 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
179
180 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
181 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALCONNECTOR, &pThis->ISerialConnector);
182 return NULL;
183}
184
185
186/* -=-=-=-=- ISerialConnector -=-=-=-=- */
187
188/** @interface_method_impl{PDMISERIALCONNECTOR,pfnDataAvailWrNotify} */
189static DECLCALLBACK(int) drvHostSerialDataAvailWrNotify(PPDMISERIALCONNECTOR pInterface, size_t cbAvail)
190{
191 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
192
193 int rc = VINF_SUCCESS;
194 size_t cbAvailOld = ASMAtomicAddZ(&pThis->cbAvailWr, cbAvail);
195 if (!cbAvailOld)
196 rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
197
198 return rc;
199}
200
201
202/**
203 * @interface_method_impl{PDMISERIALCONNECTOR,pfnReadRdr}
204 */
205static DECLCALLBACK(int) drvHostSerialReadRdr(PPDMISERIALCONNECTOR pInterface, void *pvBuf,
206 size_t cbRead, size_t *pcbRead)
207{
208 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
209 int rc = VINF_SUCCESS;
210 uint8_t *pbDst = (uint8_t *)pvBuf;
211 size_t cbReadAll = 0;
212
213 do
214 {
215 void *pvSrc = NULL;
216 size_t cbThisRead = RT_MIN(drvHostSerialReadBufGetRead(pThis, &pvSrc), cbRead);
217 if (cbThisRead)
218 {
219 memcpy(pbDst, pvSrc, cbThisRead);
220 cbRead -= cbThisRead;
221 pbDst += cbThisRead;
222 cbReadAll += cbThisRead;
223 drvHostSerialReadBufReadAdv(pThis, cbThisRead);
224 }
225 else
226 break;
227 } while (cbRead > 0);
228
229 *pcbRead = cbReadAll;
230 /* Kick the I/O thread if there is nothing to read to recalculate the poll flags. */
231 if (!drvHostSerialReadBufGetRead(pThis, NULL))
232 rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
233
234 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbReadAll);
235 return rc;
236}
237
238
239/**
240 * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgParams}
241 */
242static DECLCALLBACK(int) drvHostSerialChgParams(PPDMISERIALCONNECTOR pInterface, uint32_t uBps,
243 PDMSERIALPARITY enmParity, unsigned cDataBits,
244 PDMSERIALSTOPBITS enmStopBits)
245{
246 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
247 RTSERIALPORTCFG Cfg;
248
249 Cfg.uBaudRate = uBps;
250
251 switch (enmParity)
252 {
253 case PDMSERIALPARITY_EVEN:
254 Cfg.enmParity = RTSERIALPORTPARITY_EVEN;
255 break;
256 case PDMSERIALPARITY_ODD:
257 Cfg.enmParity = RTSERIALPORTPARITY_ODD;
258 break;
259 case PDMSERIALPARITY_NONE:
260 Cfg.enmParity = RTSERIALPORTPARITY_NONE;
261 break;
262 case PDMSERIALPARITY_MARK:
263 Cfg.enmParity = RTSERIALPORTPARITY_MARK;
264 break;
265 case PDMSERIALPARITY_SPACE:
266 Cfg.enmParity = RTSERIALPORTPARITY_SPACE;
267 break;
268 default:
269 AssertMsgFailed(("Unsupported parity setting %d\n", enmParity)); /* Should not happen. */
270 Cfg.enmParity = RTSERIALPORTPARITY_NONE;
271 }
272
273 switch (cDataBits)
274 {
275 case 5:
276 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
277 break;
278 case 6:
279 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
280 break;
281 case 7:
282 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
283 break;
284 case 8:
285 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
286 break;
287 default:
288 AssertMsgFailed(("Unsupported data bit count %u\n", cDataBits)); /* Should not happen. */
289 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
290 }
291
292 switch (enmStopBits)
293 {
294 case PDMSERIALSTOPBITS_ONE:
295 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
296 break;
297 case PDMSERIALSTOPBITS_ONEPOINTFIVE:
298 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
299 break;
300 case PDMSERIALSTOPBITS_TWO:
301 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
302 break;
303 default:
304 AssertMsgFailed(("Unsupported stop bit count %d\n", enmStopBits)); /* Should not happen. */
305 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
306 }
307
308 return RTSerialPortCfgSet(pThis->hSerialPort, &Cfg, NULL);
309}
310
311
312/**
313 * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgModemLines}
314 */
315static DECLCALLBACK(int) drvHostSerialChgModemLines(PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)
316{
317 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
318
319 uint32_t fClear = 0;
320 uint32_t fSet = 0;
321
322 if (fRts)
323 fSet |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
324 else
325 fClear |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
326
327 if (fDtr)
328 fSet |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
329 else
330 fClear |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
331
332 return RTSerialPortChgStatusLines(pThis->hSerialPort, fClear, fSet);
333}
334
335
336/**
337 * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgBrk}
338 */
339static DECLCALLBACK(int) drvHostSerialChgBrk(PPDMISERIALCONNECTOR pInterface, bool fBrk)
340{
341 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
342
343 return RTSerialPortChgBreakCondition(pThis->hSerialPort, fBrk);
344}
345
346
347/**
348 * @interface_method_impl{PDMISERIALCONNECTOR,pfnQueryStsLines}
349 */
350static DECLCALLBACK(int) drvHostSerialQueryStsLines(PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)
351{
352 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
353
354 return RTSerialPortQueryStatusLines(pThis->hSerialPort, pfStsLines);
355}
356
357
358/* -=-=-=-=- I/O thread -=-=-=-=- */
359
360/**
361 * I/O thread loop.
362 *
363 * @returns VINF_SUCCESS.
364 * @param pDrvIns PDM driver instance data.
365 * @param pThread The PDM thread data.
366 */
367static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
368{
369 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
370
371 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
372 return VINF_SUCCESS;
373
374 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
375 {
376 uint32_t fEvtFlags = RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED | RTSERIALPORT_EVT_F_BREAK_DETECTED;
377
378 /* Wait until there is room again if there is anyting to send. */
379 if ( pThis->cbAvailWr
380 || pThis->cbTxUsed)
381 fEvtFlags |= RTSERIALPORT_EVT_F_DATA_TX;
382
383 /* Try to receive more if there is still room. */
384 if (drvHostSerialReadBufGetWrite(pThis, NULL) > 0)
385 fEvtFlags |= RTSERIALPORT_EVT_F_DATA_RX;
386
387 uint32_t fEvtsRecv = 0;
388 int rc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv, RT_INDEFINITE_WAIT);
389 if (RT_SUCCESS(rc))
390 {
391 if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_TX)
392 {
393 if (pThis->cbAvailWr)
394 {
395 /* Stuff as much data into the TX buffer as we can. */
396 size_t cbToFetch = RT_ELEMENTS(pThis->abTxBuf) - pThis->cbTxUsed;
397 size_t cbFetched = 0;
398 rc = pThis->pDrvSerialPort->pfnReadWr(pThis->pDrvSerialPort, &pThis->abTxBuf[pThis->cbTxUsed], cbToFetch,
399 &cbFetched);
400 AssertRC(rc);
401
402 ASMAtomicSubZ(&pThis->cbAvailWr, cbFetched);
403 pThis->cbTxUsed += cbFetched;
404 }
405
406 size_t cbProcessed = 0;
407 rc = RTSerialPortWriteNB(pThis->hSerialPort, &pThis->abTxBuf[0], pThis->cbTxUsed, &cbProcessed);
408 if (RT_SUCCESS(rc))
409 {
410 pThis->cbTxUsed -= cbProcessed;
411 if (pThis->cbTxUsed)
412 {
413 /* Move the data in the TX buffer to the front to fill the end again. */
414 memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed);
415 }
416 else
417 pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort);
418 STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbProcessed);
419 }
420 else
421 {
422 LogRelMax(10, ("HostSerial#%d: Sending data failed even though the serial port is marked as writeable (rc=%Rrc)\n",
423 pThis->pDrvIns->iInstance, rc));
424 break;
425 }
426 }
427
428 if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_RX)
429 {
430 void *pvDst = NULL;
431 size_t cbToRead = drvHostSerialReadBufGetWrite(pThis, &pvDst);
432 size_t cbRead = 0;
433 rc = RTSerialPortReadNB(pThis->hSerialPort, pvDst, cbToRead, &cbRead);
434 if (RT_SUCCESS(rc))
435 {
436 drvHostSerialReadBufWriteAdv(pThis, cbRead);
437 /* Notify the device/driver above. */
438 rc = pThis->pDrvSerialPort->pfnDataAvailRdrNotify(pThis->pDrvSerialPort, cbRead);
439 AssertRC(rc);
440 }
441 else
442 LogRelMax(10, ("HostSerial#%d: Reading data failed even though the serial port is marked as readable (rc=%Rrc)\n",
443 pThis->pDrvIns->iInstance, rc));
444 }
445
446 if (fEvtsRecv & RTSERIALPORT_EVT_F_BREAK_DETECTED)
447 pThis->pDrvSerialPort->pfnNotifyBrk(pThis->pDrvSerialPort);
448
449 if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
450 {
451 /* The status lines have changed. Notify the device. */
452 uint32_t fStsLines = 0;
453 rc = RTSerialPortQueryStatusLines(pThis->hSerialPort, &fStsLines);
454 if (RT_SUCCESS(rc))
455 {
456 uint32_t fPdmStsLines = 0;
457
458 if (fStsLines & RTSERIALPORT_STS_LINE_DCD)
459 fPdmStsLines |= PDMISERIALPORT_STS_LINE_DCD;
460 if (fStsLines & RTSERIALPORT_STS_LINE_RI)
461 fPdmStsLines |= PDMISERIALPORT_STS_LINE_RI;
462 if (fStsLines & RTSERIALPORT_STS_LINE_DSR)
463 fPdmStsLines |= PDMISERIALPORT_STS_LINE_DSR;
464 if (fStsLines & RTSERIALPORT_STS_LINE_CTS)
465 fPdmStsLines |= PDMISERIALPORT_STS_LINE_CTS;
466
467 rc = pThis->pDrvSerialPort->pfnNotifyStsLinesChanged(pThis->pDrvSerialPort, fPdmStsLines);
468 if (RT_FAILURE(rc))
469 {
470 /* Notifying device failed, continue but log it */
471 LogRelMax(10, ("HostSerial#%d: Notifying device about changed status lines failed with error %Rrc; continuing.\n",
472 pDrvIns->iInstance, rc));
473 }
474 }
475 else
476 LogRelMax(10, ("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
477 }
478
479 if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED)
480 LogRel(("HostSerial#%d: Status line monitoring failed at a lower level and is disabled\n", pDrvIns->iInstance));
481 }
482 else if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
483 {
484 /* Getting interrupted or running into a timeout are no error conditions. */
485 rc = VINF_SUCCESS;
486 }
487 }
488
489 return VINF_SUCCESS;
490}
491
492
493/**
494 * Unblock the send thread so it can respond to a state change.
495 *
496 * @returns a VBox status code.
497 * @param pDrvIns The driver instance.
498 * @param pThread The send thread.
499 */
500static DECLCALLBACK(int) drvHostSerialWakeupIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
501{
502 RT_NOREF(pThread);
503 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
504
505 return RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
506}
507
508
509/* -=-=-=-=- driver interface -=-=-=-=- */
510
511/**
512 * Destruct a char driver instance.
513 *
514 * Most VM resources are freed by the VM. This callback is provided so that
515 * any non-VM resources can be freed correctly.
516 *
517 * @param pDrvIns The driver instance data.
518 */
519static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
520{
521 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
522 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
523 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
524
525 if (pThis->hSerialPort != NIL_RTSERIALPORT)
526 {
527 RTSerialPortClose(pThis->hSerialPort);
528 pThis->hSerialPort = NIL_RTSERIALPORT;
529 }
530
531 if (pThis->pszDevicePath)
532 {
533 MMR3HeapFree(pThis->pszDevicePath);
534 pThis->pszDevicePath = NULL;
535 }
536}
537
538
539/**
540 * Construct a char driver instance.
541 *
542 * @copydoc FNPDMDRVCONSTRUCT
543 */
544static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
545{
546 RT_NOREF1(fFlags);
547 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
548 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
549 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
550
551 /*
552 * Init basic data members and interfaces.
553 */
554 pThis->pDrvIns = pDrvIns;
555 pThis->hSerialPort = NIL_RTSERIALPORT;
556 pThis->cbAvailWr = 0;
557 pThis->cbTxUsed = 0;
558 pThis->offWrite = 0;
559 pThis->offRead = 0;
560 pThis->cbReadBuf = 0;
561 /* IBase. */
562 pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
563 /* ISerialConnector. */
564 pThis->ISerialConnector.pfnDataAvailWrNotify = drvHostSerialDataAvailWrNotify;
565 pThis->ISerialConnector.pfnReadRdr = drvHostSerialReadRdr;
566 pThis->ISerialConnector.pfnChgParams = drvHostSerialChgParams;
567 pThis->ISerialConnector.pfnChgModemLines = drvHostSerialChgModemLines;
568 pThis->ISerialConnector.pfnChgBrk = drvHostSerialChgBrk;
569 pThis->ISerialConnector.pfnQueryStsLines = drvHostSerialQueryStsLines;
570
571 /*
572 * Query configuration.
573 */
574 /* Device */
575 int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath);
576 if (RT_FAILURE(rc))
577 {
578 AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc));
579 return rc;
580 }
581
582 /*
583 * Open the device
584 */
585 uint32_t fOpenFlags = RTSERIALPORT_OPEN_F_READ
586 | RTSERIALPORT_OPEN_F_WRITE
587 | RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING
588 | RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION;
589 rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
590 if (rc == VERR_NOT_SUPPORTED)
591 {
592 /*
593 * For certain devices (or pseudo terminals) status line monitoring does not work
594 * so try again without it.
595 */
596 fOpenFlags &= ~RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING;
597 rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
598 }
599
600 if (RT_FAILURE(rc))
601 {
602 AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pThis->pszDevicePath, rc));
603 switch (rc)
604 {
605 case VERR_ACCESS_DENIED:
606 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
607#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
608 N_("Cannot open host device '%s' for read/write access. Check the permissions "
609 "of that device ('/bin/ls -l %s'): Most probably you need to be member "
610 "of the device group. Make sure that you logout/login after changing "
611 "the group settings of the current user"),
612#else
613 N_("Cannot open host device '%s' for read/write access. Check the permissions "
614 "of that device"),
615#endif
616 pThis->pszDevicePath, pThis->pszDevicePath);
617 default:
618 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
619 N_("Failed to open host device '%s'"),
620 pThis->pszDevicePath);
621 }
622 }
623
624 /*
625 * Get the ISerialPort interface of the above driver/device.
626 */
627 pThis->pDrvSerialPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISERIALPORT);
628 if (!pThis->pDrvSerialPort)
629 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no serial port interface above"), pDrvIns->iInstance);
630
631 /*
632 * Create the I/O thread.
633 */
634 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pIoThrd, pThis, drvHostSerialIoThread, drvHostSerialWakeupIoThread, 0, RTTHREADTYPE_IO, "SerIo");
635 if (RT_FAILURE(rc))
636 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create I/O thread"), pDrvIns->iInstance);
637
638 /*
639 * Register release statistics.
640 */
641 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
642 "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
643 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
644 "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
645
646 return VINF_SUCCESS;
647}
648
649/**
650 * Char driver registration record.
651 */
652const PDMDRVREG g_DrvHostSerial =
653{
654 /* u32Version */
655 PDM_DRVREG_VERSION,
656 /* szName */
657 "Host Serial",
658 /* szRCMod */
659 "",
660 /* szR0Mod */
661 "",
662 /* pszDescription */
663 "Host serial driver.",
664 /* fFlags */
665 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
666 /* fClass. */
667 PDM_DRVREG_CLASS_CHAR,
668 /* cMaxInstances */
669 ~0U,
670 /* cbInstance */
671 sizeof(DRVHOSTSERIAL),
672 /* pfnConstruct */
673 drvHostSerialConstruct,
674 /* pfnDestruct */
675 drvHostSerialDestruct,
676 /* pfnRelocate */
677 NULL,
678 /* pfnIOCtl */
679 NULL,
680 /* pfnPowerOn */
681 NULL,
682 /* pfnReset */
683 NULL,
684 /* pfnSuspend */
685 NULL,
686 /* pfnResume */
687 NULL,
688 /* pfnAttach */
689 NULL,
690 /* pfnDetach */
691 NULL,
692 /* pfnPowerOff */
693 NULL,
694 /* pfnSoftReset */
695 NULL,
696 /* u32EndVersion */
697 PDM_DRVREG_VERSION
698};
699
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