~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-proposed

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Serial/DrvHostSerial.cpp

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: DrvHostSerial.cpp $ */
 
2
/** @file
 
3
 * VBox stream I/O devices: Host serial driver
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2012 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/err.h>
 
26
 
 
27
#include <VBox/log.h>
 
28
#include <iprt/asm.h>
 
29
#include <iprt/assert.h>
 
30
#include <iprt/file.h>
 
31
#include <iprt/mem.h>
 
32
#include <iprt/pipe.h>
 
33
#include <iprt/semaphore.h>
 
34
#include <iprt/uuid.h>
 
35
 
 
36
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
37
# include <errno.h>
 
38
# ifdef RT_OS_SOLARIS
 
39
#  include <sys/termios.h>
 
40
# else
 
41
#  include <termios.h>
 
42
# endif
 
43
# include <sys/types.h>
 
44
# include <fcntl.h>
 
45
# include <string.h>
 
46
# include <unistd.h>
 
47
# ifdef RT_OS_DARWIN
 
48
#  include <sys/select.h>
 
49
# else
 
50
#  include <sys/poll.h>
 
51
# endif
 
52
# include <sys/ioctl.h>
 
53
# include <pthread.h>
 
54
 
 
55
# ifdef RT_OS_LINUX
 
56
/*
 
57
 * TIOCM_LOOP is not defined in the above header files for some reason but in asm/termios.h.
 
58
 * But inclusion of this file however leads to compilation errors because of redefinition of some
 
59
 * structs. That's why it is defined here until a better solution is found.
 
60
 */
 
61
#  ifndef TIOCM_LOOP
 
62
#   define TIOCM_LOOP 0x8000
 
63
#  endif
 
64
/* For linux custom baudrate code we also need serial_struct */
 
65
#  include <linux/serial.h>
 
66
# endif /* linux */
 
67
 
 
68
#elif defined(RT_OS_WINDOWS)
 
69
# include <Windows.h>
 
70
#endif
 
71
 
 
72
#include "VBoxDD.h"
 
73
 
 
74
 
 
75
/*******************************************************************************
 
76
*   Structures and Typedefs                                                    *
 
77
*******************************************************************************/
 
78
 
 
79
/**
 
80
 * Char driver instance data.
 
81
 *
 
82
 * @implements  PDMICHARCONNECTOR
 
83
 */
 
84
typedef struct DRVHOSTSERIAL
 
85
{
 
86
    /** Pointer to the driver instance structure. */
 
87
    PPDMDRVINS                  pDrvIns;
 
88
    /** Pointer to the char port interface of the driver/device above us. */
 
89
    PPDMICHARPORT               pDrvCharPort;
 
90
    /** Our char interface. */
 
91
    PDMICHARCONNECTOR           ICharConnector;
 
92
    /** Receive thread. */
 
93
    PPDMTHREAD                  pRecvThread;
 
94
    /** Send thread. */
 
95
    PPDMTHREAD                  pSendThread;
 
96
    /** Status lines monitor thread. */
 
97
    PPDMTHREAD                  pMonitorThread;
 
98
    /** Send event semaphore */
 
99
    RTSEMEVENT                  SendSem;
 
100
 
 
101
    /** the device path */
 
102
    char                        *pszDevicePath;
 
103
 
 
104
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
105
    /** the device handle */
 
106
    RTFILE                      hDeviceFile;
 
107
# ifdef RT_OS_DARWIN
 
108
    /** The device handle used for reading.
 
109
     * Used to prevent the read select from blocking the writes. */
 
110
    RTFILE                      hDeviceFileR;
 
111
# endif
 
112
    /** The read end of the control pipe */
 
113
    RTPIPE                      hWakeupPipeR;
 
114
    /** The write end of the control pipe */
 
115
    RTPIPE                      hWakeupPipeW;
 
116
# ifndef RT_OS_LINUX
 
117
    /** The current line status.
 
118
     * Used by the polling version of drvHostSerialMonitorThread.  */
 
119
    int                         fStatusLines;
 
120
# endif
 
121
#elif defined(RT_OS_WINDOWS)
 
122
    /** the device handle */
 
123
    HANDLE                      hDeviceFile;
 
124
    /** The event semaphore for waking up the receive thread */
 
125
    HANDLE                      hHaltEventSem;
 
126
    /** The event semaphore for overlapped receiving */
 
127
    HANDLE                      hEventRecv;
 
128
    /** For overlapped receiving */
 
129
    OVERLAPPED                  overlappedRecv;
 
130
    /** The event semaphore for overlapped sending */
 
131
    HANDLE                      hEventSend;
 
132
    /** For overlapped sending */
 
133
    OVERLAPPED                  overlappedSend;
 
134
#endif
 
135
 
 
136
    /** Internal send FIFO queue */
 
137
    uint8_t volatile            u8SendByte;
 
138
    bool volatile               fSending;
 
139
    uint8_t                     Alignment[2];
 
140
 
 
141
    /** Read/write statistics */
 
142
    STAMCOUNTER                 StatBytesRead;
 
143
    STAMCOUNTER                 StatBytesWritten;
 
144
#ifdef RT_OS_DARWIN
 
145
    /** The number of bytes we've dropped because the send queue
 
146
     * was full. */
 
147
    STAMCOUNTER                 StatSendOverflows;
 
148
#endif
 
149
} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
 
150
 
 
151
 
 
152
/** Converts a pointer to DRVCHAR::ICharConnector to a PDRVHOSTSERIAL. */
 
153
#define PDMICHAR_2_DRVHOSTSERIAL(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector)
 
154
 
 
155
 
 
156
/* -=-=-=-=- IBase -=-=-=-=- */
 
157
 
 
158
/**
 
159
 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
 
160
 */
 
161
static DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
 
162
{
 
163
    PPDMDRVINS      pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
 
164
    PDRVHOSTSERIAL  pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
165
 
 
166
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
 
167
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARCONNECTOR, &pThis->ICharConnector);
 
168
    return NULL;
 
169
}
 
170
 
 
171
 
 
172
/* -=-=-=-=- ICharConnector -=-=-=-=- */
 
173
 
 
174
/** @copydoc PDMICHARCONNECTOR::pfnWrite */
 
175
static DECLCALLBACK(int) drvHostSerialWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
 
176
{
 
177
    PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
 
178
    const uint8_t *pbBuffer = (const uint8_t *)pvBuf;
 
179
 
 
180
    LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
 
181
 
 
182
    for (uint32_t i = 0; i < cbWrite; i++)
 
183
    {
 
184
        if (ASMAtomicXchgBool(&pThis->fSending, true))
 
185
            return VERR_BUFFER_OVERFLOW;
 
186
 
 
187
        pThis->u8SendByte = pbBuffer[i];
 
188
        RTSemEventSignal(pThis->SendSem);
 
189
        STAM_COUNTER_INC(&pThis->StatBytesWritten);
 
190
    }
 
191
    return VINF_SUCCESS;
 
192
}
 
193
 
 
194
static DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
 
195
{
 
196
    PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
 
197
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
198
    struct termios *termiosSetup;
 
199
    int baud_rate;
 
200
#elif defined(RT_OS_WINDOWS)
 
201
    LPDCB comSetup;
 
202
#endif
 
203
 
 
204
    LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
 
205
 
 
206
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
 
207
    termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios));
 
208
 
 
209
    /* Enable receiver */
 
210
    termiosSetup->c_cflag |= (CLOCAL | CREAD);
 
211
 
 
212
    switch (Bps)
 
213
    {
 
214
        case 50:
 
215
            baud_rate = B50;
 
216
            break;
 
217
        case 75:
 
218
            baud_rate = B75;
 
219
            break;
 
220
        case 110:
 
221
            baud_rate = B110;
 
222
            break;
 
223
        case 134:
 
224
            baud_rate = B134;
 
225
            break;
 
226
        case 150:
 
227
            baud_rate = B150;
 
228
            break;
 
229
        case 200:
 
230
            baud_rate = B200;
 
231
            break;
 
232
        case 300:
 
233
            baud_rate = B300;
 
234
            break;
 
235
        case 600:
 
236
            baud_rate = B600;
 
237
            break;
 
238
        case 1200:
 
239
            baud_rate = B1200;
 
240
            break;
 
241
        case 1800:
 
242
            baud_rate = B1800;
 
243
            break;
 
244
        case 2400:
 
245
            baud_rate = B2400;
 
246
            break;
 
247
        case 4800:
 
248
            baud_rate = B4800;
 
249
            break;
 
250
        case 9600:
 
251
            baud_rate = B9600;
 
252
            break;
 
253
        case 19200:
 
254
            baud_rate = B19200;
 
255
            break;
 
256
        case 38400:
 
257
            baud_rate = B38400;
 
258
            break;
 
259
        case 57600:
 
260
            baud_rate = B57600;
 
261
            break;
 
262
        case 115200:
 
263
            baud_rate = B115200;
 
264
            break;
 
265
        default:
 
266
#ifdef RT_OS_LINUX
 
267
            struct serial_struct serialStruct;
 
268
            if (ioctl(RTFileToNative(pThis->hDeviceFile), TIOCGSERIAL, &serialStruct) != -1)
 
269
            {
 
270
                serialStruct.custom_divisor = serialStruct.baud_base / Bps;
 
271
                if (!serialStruct.custom_divisor)
 
272
                    serialStruct.custom_divisor = 1;
 
273
                serialStruct.flags &= ~ASYNC_SPD_MASK;
 
274
                serialStruct.flags |= ASYNC_SPD_CUST;
 
275
                ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSSERIAL, &serialStruct);
 
276
                baud_rate = B38400;
 
277
            }
 
278
            else
 
279
                baud_rate = B9600;
 
280
#else /* !RT_OS_LINUX */
 
281
            baud_rate = B9600;
 
282
#endif /* !RT_OS_LINUX */
 
283
    }
 
284
 
 
285
    cfsetispeed(termiosSetup, baud_rate);
 
286
    cfsetospeed(termiosSetup, baud_rate);
 
287
 
 
288
    switch (chParity)
 
289
    {
 
290
        case 'E':
 
291
            termiosSetup->c_cflag |= PARENB;
 
292
            break;
 
293
        case 'O':
 
294
            termiosSetup->c_cflag |= (PARENB | PARODD);
 
295
            break;
 
296
        case 'N':
 
297
            break;
 
298
        default:
 
299
            break;
 
300
    }
 
301
 
 
302
    switch (cDataBits)
 
303
    {
 
304
        case 5:
 
305
            termiosSetup->c_cflag |= CS5;
 
306
            break;
 
307
        case 6:
 
308
            termiosSetup->c_cflag |= CS6;
 
309
            break;
 
310
        case 7:
 
311
            termiosSetup->c_cflag |= CS7;
 
312
            break;
 
313
        case 8:
 
314
            termiosSetup->c_cflag |= CS8;
 
315
            break;
 
316
        default:
 
317
            break;
 
318
    }
 
319
 
 
320
    switch (cStopBits)
 
321
    {
 
322
        case 2:
 
323
            termiosSetup->c_cflag |= CSTOPB;
 
324
        default:
 
325
            break;
 
326
    }
 
327
 
 
328
    /* set serial port to raw input */
 
329
    termiosSetup->c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ECHOK | ISIG | IEXTEN);
 
330
 
 
331
    tcsetattr(RTFileToNative(pThis->hDeviceFile), TCSANOW, termiosSetup);
 
332
    RTMemTmpFree(termiosSetup);
 
333
 
 
334
#ifdef RT_OS_LINUX
 
335
    /*
 
336
     * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
 
337
     * waiting in ioctl for a modem status change then 8250.c wrongly disables
 
338
     * modem irqs and so the monitor thread never gets released. The workaround
 
339
     * is to send a signal after each tcsetattr.
 
340
     */
 
341
    RTThreadPoke(pThis->pMonitorThread->Thread);
 
342
#endif
 
343
 
 
344
#elif defined(RT_OS_WINDOWS)
 
345
    comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
 
346
 
 
347
    comSetup->DCBlength = sizeof(DCB);
 
348
 
 
349
    switch (Bps)
 
350
    {
 
351
        case 110:
 
352
            comSetup->BaudRate = CBR_110;
 
353
            break;
 
354
        case 300:
 
355
            comSetup->BaudRate = CBR_300;
 
356
            break;
 
357
        case 600:
 
358
            comSetup->BaudRate = CBR_600;
 
359
            break;
 
360
        case 1200:
 
361
            comSetup->BaudRate = CBR_1200;
 
362
            break;
 
363
        case 2400:
 
364
            comSetup->BaudRate = CBR_2400;
 
365
            break;
 
366
        case 4800:
 
367
            comSetup->BaudRate = CBR_4800;
 
368
            break;
 
369
        case 9600:
 
370
            comSetup->BaudRate = CBR_9600;
 
371
            break;
 
372
        case 14400:
 
373
            comSetup->BaudRate = CBR_14400;
 
374
            break;
 
375
        case 19200:
 
376
            comSetup->BaudRate = CBR_19200;
 
377
            break;
 
378
        case 38400:
 
379
            comSetup->BaudRate = CBR_38400;
 
380
            break;
 
381
        case 57600:
 
382
            comSetup->BaudRate = CBR_57600;
 
383
            break;
 
384
        case 115200:
 
385
            comSetup->BaudRate = CBR_115200;
 
386
            break;
 
387
        default:
 
388
            comSetup->BaudRate = CBR_9600;
 
389
    }
 
390
 
 
391
    comSetup->fBinary = TRUE;
 
392
    comSetup->fOutxCtsFlow = FALSE;
 
393
    comSetup->fOutxDsrFlow = FALSE;
 
394
    comSetup->fDtrControl = DTR_CONTROL_DISABLE;
 
395
    comSetup->fDsrSensitivity = FALSE;
 
396
    comSetup->fTXContinueOnXoff = TRUE;
 
397
    comSetup->fOutX = FALSE;
 
398
    comSetup->fInX = FALSE;
 
399
    comSetup->fErrorChar = FALSE;
 
400
    comSetup->fNull = FALSE;
 
401
    comSetup->fRtsControl = RTS_CONTROL_DISABLE;
 
402
    comSetup->fAbortOnError = FALSE;
 
403
    comSetup->wReserved = 0;
 
404
    comSetup->XonLim = 5;
 
405
    comSetup->XoffLim = 5;
 
406
    comSetup->ByteSize = cDataBits;
 
407
 
 
408
    switch (chParity)
 
409
    {
 
410
        case 'E':
 
411
            comSetup->Parity = EVENPARITY;
 
412
            break;
 
413
        case 'O':
 
414
            comSetup->Parity = ODDPARITY;
 
415
            break;
 
416
        case 'N':
 
417
            comSetup->Parity = NOPARITY;
 
418
            break;
 
419
        default:
 
420
            break;
 
421
    }
 
422
 
 
423
    switch (cStopBits)
 
424
    {
 
425
        case 1:
 
426
            comSetup->StopBits = ONESTOPBIT;
 
427
            break;
 
428
        case 2:
 
429
            comSetup->StopBits = TWOSTOPBITS;
 
430
            break;
 
431
        default:
 
432
            break;
 
433
    }
 
434
 
 
435
    comSetup->XonChar = 0;
 
436
    comSetup->XoffChar = 0;
 
437
    comSetup->ErrorChar = 0;
 
438
    comSetup->EofChar = 0;
 
439
    comSetup->EvtChar = 0;
 
440
 
 
441
    SetCommState(pThis->hDeviceFile, comSetup);
 
442
    RTMemTmpFree(comSetup);
 
443
#endif /* RT_OS_WINDOWS */
 
444
 
 
445
    return VINF_SUCCESS;
 
446
}
 
447
 
 
448
/* -=-=-=-=- receive thread -=-=-=-=- */
 
449
 
 
450
/**
 
451
 * Send thread loop.
 
452
 *
 
453
 * @returns VINF_SUCCESS.
 
454
 * @param   ThreadSelf  Thread handle to this thread.
 
455
 * @param   pvUser      User argument.
 
456
 */
 
457
static DECLCALLBACK(int) drvHostSerialSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
 
458
{
 
459
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
460
 
 
461
    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
 
462
        return VINF_SUCCESS;
 
463
 
 
464
#ifdef RT_OS_WINDOWS
 
465
    /* Make sure that the halt event semaphore is reset. */
 
466
    DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
 
467
 
 
468
    HANDLE haWait[2];
 
469
    haWait[0] = pThis->hEventSend;
 
470
    haWait[1] = pThis->hHaltEventSem;
 
471
#endif
 
472
 
 
473
    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
 
474
    {
 
475
        int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT);
 
476
        if (RT_FAILURE(rc))
 
477
            break;
 
478
 
 
479
        /*
 
480
         * Write the character to the host device.
 
481
         */
 
482
        while (pThread->enmState == PDMTHREADSTATE_RUNNING)
 
483
        {
 
484
            /* copy the send queue so we get a linear buffer with the maximal size. */
 
485
            uint8_t ch = pThis->u8SendByte;
 
486
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
487
 
 
488
            size_t cbWritten;
 
489
            rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
 
490
            if (rc == VERR_TRY_AGAIN)
 
491
                cbWritten = 0;
 
492
            if (cbWritten < 1 && (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN))
 
493
            {
 
494
                /* ok, block till the device is ready for more (O_NONBLOCK) effect. */
 
495
                rc = VINF_SUCCESS;
 
496
                while (pThread->enmState == PDMTHREADSTATE_RUNNING)
 
497
                {
 
498
                    /* wait */
 
499
                    fd_set WrSet;
 
500
                    FD_ZERO(&WrSet);
 
501
                    FD_SET(RTFileToNative(pThis->hDeviceFile), &WrSet);
 
502
                    fd_set XcptSet;
 
503
                    FD_ZERO(&XcptSet);
 
504
                    FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
 
505
# ifdef DEBUG
 
506
                    uint64_t u64Now = RTTimeMilliTS();
 
507
# endif
 
508
                    rc = select(RTFileToNative(pThis->hDeviceFile) + 1, NULL, &WrSet, &XcptSet, NULL);
 
509
                    /** @todo check rc? */
 
510
 
 
511
# ifdef DEBUG
 
512
                    Log2(("select wait for %dms\n", RTTimeMilliTS() - u64Now));
 
513
# endif
 
514
                    /* try write more */
 
515
                    rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
 
516
                    if (rc == VERR_TRY_AGAIN)
 
517
                        cbWritten = 0;
 
518
                    else if (RT_FAILURE(rc))
 
519
                        break;
 
520
                    else if (cbWritten >= 1)
 
521
                        break;
 
522
                    rc = VINF_SUCCESS;
 
523
                } /* wait/write loop */
 
524
            }
 
525
 
 
526
#elif defined(RT_OS_WINDOWS)
 
527
            /* perform an overlapped write operation. */
 
528
            DWORD cbWritten;
 
529
            memset(&pThis->overlappedSend, 0, sizeof(pThis->overlappedSend));
 
530
            pThis->overlappedSend.hEvent = pThis->hEventSend;
 
531
            if (!WriteFile(pThis->hDeviceFile, &ch, 1, &cbWritten, &pThis->overlappedSend))
 
532
            {
 
533
                dwRet = GetLastError();
 
534
                if (dwRet == ERROR_IO_PENDING)
 
535
                {
 
536
                    /*
 
537
                     * write blocked, wait for completion or wakeup...
 
538
                     */
 
539
                    dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
 
540
                    if (dwRet != WAIT_OBJECT_0)
 
541
                    {
 
542
                        AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
 
543
                        break;
 
544
                    }
 
545
                }
 
546
                else
 
547
                    rc = RTErrConvertFromWin32(dwRet);
 
548
            }
 
549
 
 
550
#endif /* RT_OS_WINDOWS */
 
551
            if (RT_FAILURE(rc))
 
552
            {
 
553
                LogRel(("HostSerial#%d: Serial Write failed with %Rrc; terminating send thread\n", pDrvIns->iInstance, rc));
 
554
                return rc;
 
555
            }
 
556
            ASMAtomicXchgBool(&pThis->fSending, false);
 
557
            break;
 
558
        } /* write loop */
 
559
    }
 
560
 
 
561
    return VINF_SUCCESS;
 
562
}
 
563
 
 
564
/**
 
565
 * Unblock the send thread so it can respond to a state change.
 
566
 *
 
567
 * @returns a VBox status code.
 
568
 * @param     pDrvIns     The driver instance.
 
569
 * @param     pThread     The send thread.
 
570
 */
 
571
static DECLCALLBACK(int) drvHostSerialWakeupSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD /*pThread*/)
 
572
{
 
573
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
574
    int rc;
 
575
 
 
576
    rc = RTSemEventSignal(pThis->SendSem);
 
577
    if (RT_FAILURE(rc))
 
578
        return rc;
 
579
 
 
580
#ifdef RT_OS_WINDOWS
 
581
    if (!SetEvent(pThis->hHaltEventSem))
 
582
        return RTErrConvertFromWin32(GetLastError());
 
583
#endif
 
584
 
 
585
    return VINF_SUCCESS;
 
586
}
 
587
 
 
588
/* -=-=-=-=- receive thread -=-=-=-=- */
 
589
 
 
590
/**
 
591
 * Receive thread loop.
 
592
 *
 
593
 * This thread pushes data from the host serial device up the driver
 
594
 * chain toward the serial device.
 
595
 *
 
596
 * @returns VINF_SUCCESS.
 
597
 * @param   ThreadSelf  Thread handle to this thread.
 
598
 * @param   pvUser      User argument.
 
599
 */
 
600
static DECLCALLBACK(int) drvHostSerialRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
 
601
{
 
602
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
603
    uint8_t abBuffer[256];
 
604
    uint8_t *pbBuffer = NULL;
 
605
    size_t cbRemaining = 0; /* start by reading host data */
 
606
    int rc = VINF_SUCCESS;
 
607
    int rcThread = VINF_SUCCESS;
 
608
 
 
609
    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
 
610
        return VINF_SUCCESS;
 
611
 
 
612
#ifdef RT_OS_WINDOWS
 
613
    /* Make sure that the halt event semaphore is reset. */
 
614
    DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
 
615
 
 
616
    HANDLE ahWait[2];
 
617
    ahWait[0] = pThis->hEventRecv;
 
618
    ahWait[1] = pThis->hHaltEventSem;
 
619
#endif
 
620
 
 
621
    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
 
622
    {
 
623
        if (!cbRemaining)
 
624
        {
 
625
            /* Get a block of data from the host serial device. */
 
626
 
 
627
#if defined(RT_OS_DARWIN) /* poll is broken on x86 darwin, returns POLLNVAL. */
 
628
            fd_set RdSet;
 
629
            FD_ZERO(&RdSet);
 
630
            FD_SET(RTFileToNative(pThis->hDeviceFileR), &RdSet);
 
631
            FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet);
 
632
            fd_set XcptSet;
 
633
            FD_ZERO(&XcptSet);
 
634
            FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
 
635
            FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet);
 
636
# if 1 /* it seems like this select is blocking the write... */
 
637
            rc = select(RT_MAX(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR)) + 1,
 
638
                        &RdSet, NULL, &XcptSet, NULL);
 
639
# else
 
640
            struct timeval tv = { 0, 1000 };
 
641
            rc = select(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR) + 1,
 
642
                        &RdSet, NULL, &XcptSet, &tv);
 
643
# endif
 
644
            if (rc == -1)
 
645
            {
 
646
                int err = errno;
 
647
                rcThread = RTErrConvertFromErrno(err);
 
648
                LogRel(("HostSerial#%d: select failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
 
649
                break;
 
650
            }
 
651
 
 
652
            /* this might have changed in the meantime */
 
653
            if (pThread->enmState != PDMTHREADSTATE_RUNNING)
 
654
                break;
 
655
            if (rc == 0)
 
656
                continue;
 
657
 
 
658
            /* drain the wakeup pipe */
 
659
            size_t cbRead;
 
660
            if (   FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet)
 
661
                || FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet))
 
662
            {
 
663
                rc = RTPipeRead(pThis->hWakeupPipeR, abBuffer, 1, &cbRead);
 
664
                if (RT_FAILURE(rc))
 
665
                {
 
666
                    LogRel(("HostSerial#%d: draining the wakeup pipe failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
 
667
                    rcThread = rc;
 
668
                    break;
 
669
                }
 
670
                continue;
 
671
            }
 
672
 
 
673
            /* read data from the serial port. */
 
674
            rc = RTFileRead(pThis->hDeviceFileR, abBuffer, sizeof(abBuffer), &cbRead);
 
675
            if (RT_FAILURE(rc))
 
676
            {
 
677
                LogRel(("HostSerial#%d: (1) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
 
678
                rcThread = rc;
 
679
                break;
 
680
            }
 
681
            cbRemaining = cbRead;
 
682
 
 
683
#elif defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
684
 
 
685
            size_t cbRead;
 
686
            struct pollfd aFDs[2];
 
687
            aFDs[0].fd      = RTFileToNative(pThis->hDeviceFile);
 
688
            aFDs[0].events  = POLLIN;
 
689
            aFDs[0].revents = 0;
 
690
            aFDs[1].fd      = RTPipeToNative(pThis->hWakeupPipeR);
 
691
            aFDs[1].events  = POLLIN | POLLERR | POLLHUP;
 
692
            aFDs[1].revents = 0;
 
693
            rc = poll(aFDs, RT_ELEMENTS(aFDs), -1);
 
694
            if (rc < 0)
 
695
            {
 
696
                int err = errno;
 
697
                if (err == EINTR)
 
698
                {
 
699
                    /*
 
700
                     * EINTR errors should be harmless, even if they are not supposed to occur in our setup.
 
701
                     */
 
702
                    Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, err, strerror(err)));
 
703
                    RTThreadYield();
 
704
                    continue;
 
705
                }
 
706
 
 
707
                rcThread = RTErrConvertFromErrno(err);
 
708
                LogRel(("HostSerial#%d: poll failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
 
709
                break;
 
710
            }
 
711
            /* this might have changed in the meantime */
 
712
            if (pThread->enmState != PDMTHREADSTATE_RUNNING)
 
713
                break;
 
714
            if (rc > 0 && aFDs[1].revents)
 
715
            {
 
716
                if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
 
717
                    break;
 
718
                /* notification to terminate -- drain the pipe */
 
719
                RTPipeRead(pThis->hWakeupPipeR, &abBuffer, 1, &cbRead);
 
720
                continue;
 
721
            }
 
722
            rc = RTFileRead(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
 
723
            if (RT_FAILURE(rc))
 
724
            {
 
725
                /* don't terminate worker thread when data unavailable */
 
726
                if (rc == VERR_TRY_AGAIN)
 
727
                    continue;
 
728
 
 
729
                LogRel(("HostSerial#%d: (2) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
 
730
                rcThread = rc;
 
731
                break;
 
732
            }
 
733
            cbRemaining = cbRead;
 
734
 
 
735
#elif defined(RT_OS_WINDOWS)
 
736
 
 
737
            DWORD dwEventMask = 0;
 
738
            DWORD dwNumberOfBytesTransferred;
 
739
 
 
740
            memset(&pThis->overlappedRecv, 0, sizeof(pThis->overlappedRecv));
 
741
            pThis->overlappedRecv.hEvent = pThis->hEventRecv;
 
742
 
 
743
            if (!WaitCommEvent(pThis->hDeviceFile, &dwEventMask, &pThis->overlappedRecv))
 
744
            {
 
745
                dwRet = GetLastError();
 
746
                if (dwRet == ERROR_IO_PENDING)
 
747
                {
 
748
                    dwRet = WaitForMultipleObjects(2, ahWait, FALSE, INFINITE);
 
749
                    if (dwRet != WAIT_OBJECT_0)
 
750
                    {
 
751
                        /* notification to terminate */
 
752
                        AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
 
753
                        break;
 
754
                    }
 
755
                }
 
756
                else
 
757
                {
 
758
                    rcThread = RTErrConvertFromWin32(dwRet);
 
759
                    LogRel(("HostSerial#%d: Wait failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
 
760
                    break;
 
761
                }
 
762
            }
 
763
            /* this might have changed in the meantime */
 
764
            if (pThread->enmState != PDMTHREADSTATE_RUNNING)
 
765
                break;
 
766
 
 
767
            /* Check the event */
 
768
            if (dwEventMask & EV_RXCHAR)
 
769
            {
 
770
                if (!ReadFile(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &pThis->overlappedRecv))
 
771
                {
 
772
                    rcThread = RTErrConvertFromWin32(GetLastError());
 
773
                    LogRel(("HostSerial#%d: Read failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
 
774
                    break;
 
775
                }
 
776
                cbRemaining = dwNumberOfBytesTransferred;
 
777
            }
 
778
            else if (dwEventMask & EV_BREAK)
 
779
            {
 
780
                Log(("HostSerial#%d: Detected break\n"));
 
781
                rc = pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort);
 
782
            }
 
783
            else
 
784
            {
 
785
                /* The status lines have changed. Notify the device. */
 
786
                DWORD dwNewStatusLinesState = 0;
 
787
                uint32_t uNewStatusLinesState = 0;
 
788
 
 
789
                /* Get the new state */
 
790
                if (GetCommModemStatus(pThis->hDeviceFile, &dwNewStatusLinesState))
 
791
                {
 
792
                    if (dwNewStatusLinesState & MS_RLSD_ON)
 
793
                        uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DCD;
 
794
                    if (dwNewStatusLinesState & MS_RING_ON)
 
795
                        uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_RI;
 
796
                    if (dwNewStatusLinesState & MS_DSR_ON)
 
797
                        uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DSR;
 
798
                    if (dwNewStatusLinesState & MS_CTS_ON)
 
799
                        uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_CTS;
 
800
                    rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, uNewStatusLinesState);
 
801
                    if (RT_FAILURE(rc))
 
802
                    {
 
803
                        /* Notifying device failed, continue but log it */
 
804
                        LogRel(("HostSerial#%d: Notifying device failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
 
805
                    }
 
806
                }
 
807
                else
 
808
                {
 
809
                    /* Getting new state failed, continue but log it */
 
810
                    LogRel(("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError())));
 
811
                }
 
812
            }
 
813
#endif
 
814
 
 
815
            Log(("Read %d bytes.\n", cbRemaining));
 
816
            pbBuffer = abBuffer;
 
817
        }
 
818
        else
 
819
        {
 
820
            /* Send data to the guest. */
 
821
            size_t cbProcessed = cbRemaining;
 
822
            rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbBuffer, &cbProcessed);
 
823
            if (RT_SUCCESS(rc))
 
824
            {
 
825
                Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
 
826
                pbBuffer += cbProcessed;
 
827
                cbRemaining -= cbProcessed;
 
828
                STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
 
829
            }
 
830
            else if (rc == VERR_TIMEOUT)
 
831
            {
 
832
                /* Normal case, just means that the guest didn't accept a new
 
833
                 * character before the timeout elapsed. Just retry. */
 
834
                rc = VINF_SUCCESS;
 
835
            }
 
836
            else
 
837
            {
 
838
                LogRel(("HostSerial#%d: NotifyRead failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
 
839
                rcThread = rc;
 
840
                break;
 
841
            }
 
842
        }
 
843
    }
 
844
 
 
845
    return rcThread;
 
846
}
 
847
 
 
848
/**
 
849
 * Unblock the send thread so it can respond to a state change.
 
850
 *
 
851
 * @returns a VBox status code.
 
852
 * @param     pDrvIns     The driver instance.
 
853
 * @param     pThread     The send thread.
 
854
 */
 
855
static DECLCALLBACK(int) drvHostSerialWakeupRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD /*pThread*/)
 
856
{
 
857
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
858
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
859
    size_t cbIgnored;
 
860
    return RTPipeWrite(pThis->hWakeupPipeW, "", 1, &cbIgnored);
 
861
 
 
862
#elif defined(RT_OS_WINDOWS)
 
863
    if (!SetEvent(pThis->hHaltEventSem))
 
864
        return RTErrConvertFromWin32(GetLastError());
 
865
    return VINF_SUCCESS;
 
866
#else
 
867
# error adapt me!
 
868
#endif
 
869
}
 
870
 
 
871
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
872
/* -=-=-=-=- Monitor thread -=-=-=-=- */
 
873
 
 
874
/**
 
875
 * Monitor thread loop.
 
876
 *
 
877
 * This thread monitors the status lines and notifies the device
 
878
 * if they change.
 
879
 *
 
880
 * @returns VINF_SUCCESS.
 
881
 * @param   ThreadSelf  Thread handle to this thread.
 
882
 * @param   pvUser      User argument.
 
883
 */
 
884
static DECLCALLBACK(int) drvHostSerialMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
 
885
{
 
886
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
887
    int rc = VINF_SUCCESS;
 
888
    unsigned long const uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
 
889
 
 
890
    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
 
891
        return VINF_SUCCESS;
 
892
 
 
893
    do
 
894
    {
 
895
        unsigned int statusLines;
 
896
 
 
897
        /*
 
898
         * Get the status line state.
 
899
         */
 
900
        rc = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &statusLines);
 
901
        if (rc < 0)
 
902
        {
 
903
            PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
 
904
                                       N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
 
905
                                       pThis->pszDevicePath, RTErrConvertFromErrno(errno));
 
906
            break;
 
907
        }
 
908
 
 
909
        uint32_t newStatusLine = 0;
 
910
 
 
911
        if (statusLines & TIOCM_CAR)
 
912
            newStatusLine |= PDMICHARPORT_STATUS_LINES_DCD;
 
913
        if (statusLines & TIOCM_RNG)
 
914
            newStatusLine |= PDMICHARPORT_STATUS_LINES_RI;
 
915
        if (statusLines & TIOCM_DSR)
 
916
            newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR;
 
917
        if (statusLines & TIOCM_CTS)
 
918
            newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS;
 
919
        pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
 
920
 
 
921
        if (PDMTHREADSTATE_RUNNING != pThread->enmState)
 
922
            break;
 
923
 
 
924
# ifdef RT_OS_LINUX
 
925
        /*
 
926
         * Wait for status line change.
 
927
         *
 
928
         * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
 
929
         * waiting in ioctl for a modem status change then 8250.c wrongly disables
 
930
         * modem irqs and so the monitor thread never gets released. The workaround
 
931
         * is to send a signal after each tcsetattr.
 
932
         */
 
933
        ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMIWAIT, uStatusLinesToCheck);
 
934
# else
 
935
        /* Poll for status line change. */
 
936
        if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
 
937
            PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
 
938
        pThis->fStatusLines = statusLines;
 
939
# endif
 
940
    }
 
941
    while (PDMTHREADSTATE_RUNNING == pThread->enmState);
 
942
 
 
943
    return VINF_SUCCESS;
 
944
}
 
945
 
 
946
/**
 
947
 * Unblock the monitor thread so it can respond to a state change.
 
948
 * We need to execute this code exactly once during initialization.
 
949
 * But we don't want to block --- therefore this dedicated thread.
 
950
 *
 
951
 * @returns a VBox status code.
 
952
 * @param     pDrvIns     The driver instance.
 
953
 * @param     pThread     The send thread.
 
954
 */
 
955
static DECLCALLBACK(int) drvHostSerialWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
 
956
{
 
957
# ifdef RT_OS_LINUX
 
958
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
959
    int rc = VINF_SUCCESS;
 
960
 
 
961
    rc = RTThreadPoke(pThread->Thread);
 
962
    if (RT_FAILURE(rc))
 
963
        PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
 
964
                                    N_("Suspending serial monitor thread failed for serial device '%s' (%Rrc). The shutdown may take longer than expected"),
 
965
                                    pThis->pszDevicePath, RTErrConvertFromErrno(rc));
 
966
 
 
967
# else  /* !RT_OS_LINUX*/
 
968
 
 
969
    /* In polling mode there is nobody to wake up (PDMThread will cancel the sleep). */
 
970
    NOREF(pDrvIns);
 
971
    NOREF(pThread);
 
972
 
 
973
# endif /* RT_OS_LINUX */
 
974
 
 
975
    return VINF_SUCCESS;
 
976
}
 
977
#endif /* RT_OS_LINUX || RT_OS_DARWIN || RT_OS_SOLARIS */
 
978
 
 
979
/**
 
980
 * Set the modem lines.
 
981
 *
 
982
 * @returns VBox status code
 
983
 * @param pInterface        Pointer to the interface structure.
 
984
 * @param RequestToSend     Set to true if this control line should be made active.
 
985
 * @param DataTerminalReady Set to true if this control line should be made active.
 
986
 */
 
987
static DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool RequestToSend, bool DataTerminalReady)
 
988
{
 
989
    PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
 
990
 
 
991
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
992
    int modemStateSet = 0;
 
993
    int modemStateClear = 0;
 
994
 
 
995
    if (RequestToSend)
 
996
        modemStateSet |= TIOCM_RTS;
 
997
    else
 
998
        modemStateClear |= TIOCM_RTS;
 
999
 
 
1000
    if (DataTerminalReady)
 
1001
        modemStateSet |= TIOCM_DTR;
 
1002
    else
 
1003
        modemStateClear |= TIOCM_DTR;
 
1004
 
 
1005
    if (modemStateSet)
 
1006
        ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIS, &modemStateSet);
 
1007
 
 
1008
    if (modemStateClear)
 
1009
        ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIC, &modemStateClear);
 
1010
 
 
1011
#elif defined(RT_OS_WINDOWS)
 
1012
    if (RequestToSend)
 
1013
        EscapeCommFunction(pThis->hDeviceFile, SETRTS);
 
1014
    else
 
1015
        EscapeCommFunction(pThis->hDeviceFile, CLRRTS);
 
1016
 
 
1017
    if (DataTerminalReady)
 
1018
        EscapeCommFunction(pThis->hDeviceFile, SETDTR);
 
1019
    else
 
1020
        EscapeCommFunction(pThis->hDeviceFile, CLRDTR);
 
1021
 
 
1022
#endif
 
1023
 
 
1024
    return VINF_SUCCESS;
 
1025
}
 
1026
 
 
1027
/**
 
1028
 * Sets the TD line into break condition.
 
1029
 *
 
1030
 * @returns VBox status code.
 
1031
 * @param   pInterface  Pointer to the interface structure containing the called function pointer.
 
1032
 * @param   fBreak      Set to true to let the device send a break false to put into normal operation.
 
1033
 * @thread  Any thread.
 
1034
 */
 
1035
static DECLCALLBACK(int) drvHostSerialSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak)
 
1036
{
 
1037
    PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
 
1038
 
 
1039
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
1040
    if (fBreak)
 
1041
        ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSBRK);
 
1042
    else
 
1043
        ioctl(RTFileToNative(pThis->hDeviceFile), TIOCCBRK);
 
1044
 
 
1045
#elif defined(RT_OS_WINDOWS)
 
1046
    if (fBreak)
 
1047
        SetCommBreak(pThis->hDeviceFile);
 
1048
    else
 
1049
        ClearCommBreak(pThis->hDeviceFile);
 
1050
#endif
 
1051
 
 
1052
    return VINF_SUCCESS;
 
1053
}
 
1054
 
 
1055
/* -=-=-=-=- driver interface -=-=-=-=- */
 
1056
 
 
1057
/**
 
1058
 * Destruct a char driver instance.
 
1059
 *
 
1060
 * Most VM resources are freed by the VM. This callback is provided so that
 
1061
 * any non-VM resources can be freed correctly.
 
1062
 *
 
1063
 * @param   pDrvIns     The driver instance data.
 
1064
 */
 
1065
static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
 
1066
{
 
1067
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
1068
    LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
 
1069
    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
 
1070
 
 
1071
    /* Empty the send queue */
 
1072
    if (pThis->SendSem != NIL_RTSEMEVENT)
 
1073
    {
 
1074
        RTSemEventDestroy(pThis->SendSem);
 
1075
        pThis->SendSem = NIL_RTSEMEVENT;
 
1076
    }
 
1077
 
 
1078
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
1079
 
 
1080
    int rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc);
 
1081
    pThis->hWakeupPipeW = NIL_RTPIPE;
 
1082
    rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc);
 
1083
    pThis->hWakeupPipeR = NIL_RTPIPE;
 
1084
 
 
1085
# if defined(RT_OS_DARWIN)
 
1086
    if (pThis->hDeviceFileR != NIL_RTFILE)
 
1087
    {
 
1088
        if (pThis->hDeviceFileR != pThis->hDeviceFile)
 
1089
        {
 
1090
            rc = RTFileClose(pThis->hDeviceFileR);
 
1091
            AssertRC(rc);
 
1092
        }
 
1093
        pThis->hDeviceFileR = NIL_RTFILE;
 
1094
    }
 
1095
# endif
 
1096
    if (pThis->hDeviceFile != NIL_RTFILE)
 
1097
    {
 
1098
        rc = RTFileClose(pThis->hDeviceFile); AssertRC(rc);
 
1099
        pThis->hDeviceFile = NIL_RTFILE;
 
1100
    }
 
1101
 
 
1102
#elif defined(RT_OS_WINDOWS)
 
1103
    CloseHandle(pThis->hEventRecv);
 
1104
    CloseHandle(pThis->hEventSend);
 
1105
    CancelIo(pThis->hDeviceFile);
 
1106
    CloseHandle(pThis->hDeviceFile);
 
1107
 
 
1108
#endif
 
1109
 
 
1110
    if (pThis->pszDevicePath)
 
1111
    {
 
1112
        MMR3HeapFree(pThis->pszDevicePath);
 
1113
        pThis->pszDevicePath = NULL;
 
1114
    }
 
1115
}
 
1116
 
 
1117
/**
 
1118
 * Construct a char driver instance.
 
1119
 *
 
1120
 * @copydoc FNPDMDRVCONSTRUCT
 
1121
 */
 
1122
static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t /*fFlags*/)
 
1123
{
 
1124
    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
 
1125
    LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
 
1126
    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
 
1127
 
 
1128
    /*
 
1129
     * Init basic data members and interfaces.
 
1130
     */
 
1131
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
1132
    pThis->hDeviceFile  = NIL_RTFILE;
 
1133
# ifdef RT_OS_DARWIN
 
1134
    pThis->hDeviceFileR = NIL_RTFILE;
 
1135
# endif
 
1136
    pThis->hWakeupPipeR = NIL_RTPIPE;
 
1137
    pThis->hWakeupPipeW = NIL_RTPIPE;
 
1138
#elif defined(RT_OS_WINDOWS)
 
1139
    pThis->hEventRecv  = INVALID_HANDLE_VALUE;
 
1140
    pThis->hEventSend  = INVALID_HANDLE_VALUE;
 
1141
    pThis->hDeviceFile = INVALID_HANDLE_VALUE;
 
1142
#endif
 
1143
    pThis->SendSem     = NIL_RTSEMEVENT;
 
1144
    /* IBase. */
 
1145
    pDrvIns->IBase.pfnQueryInterface        = drvHostSerialQueryInterface;
 
1146
    /* ICharConnector. */
 
1147
    pThis->ICharConnector.pfnWrite          = drvHostSerialWrite;
 
1148
    pThis->ICharConnector.pfnSetParameters  = drvHostSerialSetParameters;
 
1149
    pThis->ICharConnector.pfnSetModemLines  = drvHostSerialSetModemLines;
 
1150
    pThis->ICharConnector.pfnSetBreak       = drvHostSerialSetBreak;
 
1151
 
 
1152
    /*
 
1153
     * Query configuration.
 
1154
     */
 
1155
    /* Device */
 
1156
    int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath);
 
1157
    if (RT_FAILURE(rc))
 
1158
    {
 
1159
        AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc));
 
1160
        return rc;
 
1161
    }
 
1162
 
 
1163
    /*
 
1164
     * Open the device
 
1165
     */
 
1166
#ifdef RT_OS_WINDOWS
 
1167
 
 
1168
    pThis->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
 
1169
    AssertReturn(pThis->hHaltEventSem != NULL, VERR_NO_MEMORY);
 
1170
 
 
1171
    pThis->hEventRecv = CreateEvent(NULL, FALSE, FALSE, NULL);
 
1172
    AssertReturn(pThis->hEventRecv != NULL, VERR_NO_MEMORY);
 
1173
 
 
1174
    pThis->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL);
 
1175
    AssertReturn(pThis->hEventSend != NULL, VERR_NO_MEMORY);
 
1176
 
 
1177
    HANDLE hFile = CreateFile(pThis->pszDevicePath,
 
1178
                              GENERIC_READ | GENERIC_WRITE,
 
1179
                              0, // must be opened with exclusive access
 
1180
                              NULL, // no SECURITY_ATTRIBUTES structure
 
1181
                              OPEN_EXISTING, // must use OPEN_EXISTING
 
1182
                              FILE_FLAG_OVERLAPPED, // overlapped I/O
 
1183
                              NULL); // no template file
 
1184
    if (hFile == INVALID_HANDLE_VALUE)
 
1185
        rc = RTErrConvertFromWin32(GetLastError());
 
1186
    else
 
1187
    {
 
1188
        pThis->hDeviceFile = hFile;
 
1189
        /* for overlapped read */
 
1190
        if (!SetCommMask(hFile, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING | EV_RLSD))
 
1191
        {
 
1192
            LogRel(("HostSerial#%d: SetCommMask failed with error %d.\n", pDrvIns->iInstance, GetLastError()));
 
1193
            return VERR_FILE_IO_ERROR;
 
1194
        }
 
1195
        rc = VINF_SUCCESS;
 
1196
    }
 
1197
 
 
1198
#else /* !RT_OS_WINDOWS */
 
1199
 
 
1200
    uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
 
1201
# ifdef RT_OS_LINUX
 
1202
    /* This seems to be necessary on some Linux hosts, otherwise we hang here forever. */
 
1203
    fOpen |= RTFILE_O_NON_BLOCK;
 
1204
# endif
 
1205
    rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen);
 
1206
# ifdef RT_OS_LINUX
 
1207
    /* RTFILE_O_NON_BLOCK not supported? */
 
1208
    if (rc == VERR_INVALID_PARAMETER)
 
1209
        rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen & ~RTFILE_O_NON_BLOCK);
 
1210
# endif
 
1211
# ifdef RT_OS_DARWIN
 
1212
    if (RT_SUCCESS(rc))
 
1213
        rc = RTFileOpen(&pThis->hDeviceFileR, pThis->pszDevicePath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
1214
# endif
 
1215
 
 
1216
 
 
1217
#endif /* !RT_OS_WINDOWS */
 
1218
 
 
1219
    if (RT_FAILURE(rc))
 
1220
    {
 
1221
        AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pThis->pszDevicePath, rc));
 
1222
        switch (rc)
 
1223
        {
 
1224
            case VERR_ACCESS_DENIED:
 
1225
                return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
 
1226
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
1227
                                           N_("Cannot open host device '%s' for read/write access. Check the permissions "
 
1228
                                              "of that device ('/bin/ls -l %s'): Most probably you need to be member "
 
1229
                                              "of the device group. Make sure that you logout/login after changing "
 
1230
                                              "the group settings of the current user"),
 
1231
#else
 
1232
                                           N_("Cannot open host device '%s' for read/write access. Check the permissions "
 
1233
                                              "of that device"),
 
1234
#endif
 
1235
                                           pThis->pszDevicePath, pThis->pszDevicePath);
 
1236
           default:
 
1237
                return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
 
1238
                                           N_("Failed to open host device '%s'"),
 
1239
                                           pThis->pszDevicePath);
 
1240
        }
 
1241
    }
 
1242
 
 
1243
    /* Set to non blocking I/O */
 
1244
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
1245
 
 
1246
    fcntl(RTFileToNative(pThis->hDeviceFile), F_SETFL, O_NONBLOCK);
 
1247
# ifdef RT_OS_DARWIN
 
1248
    fcntl(RTFileToNative(pThis->hDeviceFileR), F_SETFL, O_NONBLOCK);
 
1249
# endif
 
1250
    rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/);
 
1251
    AssertRCReturn(rc, rc);
 
1252
 
 
1253
#elif defined(RT_OS_WINDOWS)
 
1254
 
 
1255
    /* Set the COMMTIMEOUTS to get non blocking I/O */
 
1256
    COMMTIMEOUTS comTimeout;
 
1257
 
 
1258
    comTimeout.ReadIntervalTimeout         = MAXDWORD;
 
1259
    comTimeout.ReadTotalTimeoutMultiplier  = 0;
 
1260
    comTimeout.ReadTotalTimeoutConstant    = 0;
 
1261
    comTimeout.WriteTotalTimeoutMultiplier = 0;
 
1262
    comTimeout.WriteTotalTimeoutConstant   = 0;
 
1263
 
 
1264
    SetCommTimeouts(pThis->hDeviceFile, &comTimeout);
 
1265
 
 
1266
#endif
 
1267
 
 
1268
    /*
 
1269
     * Get the ICharPort interface of the above driver/device.
 
1270
     */
 
1271
    pThis->pDrvCharPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICHARPORT);
 
1272
    if (!pThis->pDrvCharPort)
 
1273
        return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance);
 
1274
 
 
1275
    /*
 
1276
     * Create the receive, send and monitor threads plus the related send semaphore.
 
1277
     */
 
1278
    rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pRecvThread, pThis, drvHostSerialRecvThread, drvHostSerialWakeupRecvThread, 0, RTTHREADTYPE_IO, "SerRecv");
 
1279
    if (RT_FAILURE(rc))
 
1280
        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
 
1281
 
 
1282
    rc = RTSemEventCreate(&pThis->SendSem);
 
1283
    AssertRC(rc);
 
1284
 
 
1285
    rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pSendThread, pThis, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "SerSend");
 
1286
    if (RT_FAILURE(rc))
 
1287
        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
 
1288
 
 
1289
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
 
1290
    /* Linux & darwin needs a separate thread which monitors the status lines. */
 
1291
# ifndef RT_OS_LINUX
 
1292
    ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &pThis->fStatusLines);
 
1293
# endif
 
1294
    rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostSerialMonitorThread, drvHostSerialWakeupMonitorThread, 0, RTTHREADTYPE_IO, "SerMon");
 
1295
    if (RT_FAILURE(rc))
 
1296
        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create monitor thread"), pDrvIns->iInstance);
 
1297
#endif
 
1298
 
 
1299
    /*
 
1300
     * Register release statistics.
 
1301
     */
 
1302
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written",         "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
 
1303
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead,       STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read",            "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
 
1304
#ifdef RT_OS_DARWIN /* new Write code, not darwin specific. */
 
1305
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSendOverflows,   STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes overflowed",      "/Devices/HostSerial%d/SendOverflow", pDrvIns->iInstance);
 
1306
#endif
 
1307
 
 
1308
    return VINF_SUCCESS;
 
1309
}
 
1310
 
 
1311
/**
 
1312
 * Char driver registration record.
 
1313
 */
 
1314
const PDMDRVREG g_DrvHostSerial =
 
1315
{
 
1316
    /* u32Version */
 
1317
    PDM_DRVREG_VERSION,
 
1318
    /* szName */
 
1319
    "Host Serial",
 
1320
        /* szRCMod */
 
1321
    "",
 
1322
    /* szR0Mod */
 
1323
    "",
 
1324
/* pszDescription */
 
1325
    "Host serial driver.",
 
1326
    /* fFlags */
 
1327
    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
 
1328
    /* fClass. */
 
1329
    PDM_DRVREG_CLASS_CHAR,
 
1330
    /* cMaxInstances */
 
1331
    ~0U,
 
1332
    /* cbInstance */
 
1333
    sizeof(DRVHOSTSERIAL),
 
1334
    /* pfnConstruct */
 
1335
    drvHostSerialConstruct,
 
1336
    /* pfnDestruct */
 
1337
    drvHostSerialDestruct,
 
1338
    /* pfnRelocate */
 
1339
    NULL,
 
1340
    /* pfnIOCtl */
 
1341
    NULL,
 
1342
    /* pfnPowerOn */
 
1343
    NULL,
 
1344
    /* pfnReset */
 
1345
    NULL,
 
1346
    /* pfnSuspend */
 
1347
    NULL,
 
1348
    /* pfnResume */
 
1349
    NULL,
 
1350
    /* pfnAttach */
 
1351
    NULL,
 
1352
    /* pfnDetach */
 
1353
    NULL,
 
1354
    /* pfnPowerOff */
 
1355
    NULL,
 
1356
    /* pfnSoftReset */
 
1357
    NULL,
 
1358
    /* u32EndVersion */
 
1359
    PDM_DRVREG_VERSION
 
1360
};
 
1361