VirtualBox

Changeset 70800 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 29, 2018 8:55:29 PM (7 years ago)
Author:
vboxsync
Message:

Devices/Serial: Rewrite the host serial driver to use the IPRT serial port API, done in a separate file for now until it is mature enough

Location:
trunk/src/VBox/Devices
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Makefile.kmk

    r70434 r70800  
    813813 endif
    814814
     815 if defined(VBOX_WITH_NEW_DRVHOSTSERIAL)
     816  VBoxDD_SOURCES.linux := \
     817        $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.linux)) \
     818        Serial/DrvHostSerialNew.cpp
     819
     820  VBoxDD_SOURCES.darwin := \
     821        $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.darwin)) \
     822        Serial/DrvHostSerialNew.cpp
     823
     824  VBoxDD_SOURCES.win := \
     825        $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.win)) \
     826        Serial/DrvHostSerialNew.cpp
     827
     828  VBoxDD_SOURCES.freebsd := \
     829        $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.freebsd)) \
     830        Serial/DrvHostSerialNew.cpp
     831
     832  VBoxDD_SOURCES.solaris := \
     833        $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.solaris)) \
     834        Serial/DrvHostSerialNew.cpp
     835 endif
    815836
    816837 # --- Final bits, mostly libraries for order dependant linkers. ---
  • trunk/src/VBox/Devices/Serial/DrvHostSerialNew.cpp

    r70762 r70800  
    3333#include <iprt/semaphore.h>
    3434#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 <iprt/win/windows.h>
    70 #endif
     35#include <iprt/serialport.h>
    7136
    7237#include "VBoxDD.h"
     
    9055    /** Our char interface. */
    9156    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 
     57    /** I/O thread. */
     58    PPDMTHREAD                  pIoThrd;
     59    /** The serial port handle. */
     60    RTSERIALPORT                hSerialPort;
    10161    /** the device path */
    10262    char                        *pszDevicePath;
    10363
    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     /** The current line status.
    117      * Used by the polling version of drvHostSerialMonitorThread.  */
    118     int                         fStatusLines;
    119 #elif defined(RT_OS_WINDOWS)
    120     /** the device handle */
    121     HANDLE                      hDeviceFile;
    122     /** The event semaphore for waking up the receive thread */
    123     HANDLE                      hHaltEventSem;
    124     /** The event semaphore for overlapped receiving */
    125     HANDLE                      hEventRecv;
    126     /** For overlapped receiving */
    127     OVERLAPPED                  overlappedRecv;
    128     /** The event semaphore for overlapped sending */
    129     HANDLE                      hEventSend;
    130     /** For overlapped sending */
    131     OVERLAPPED                  overlappedSend;
    132 #endif
    13364
    13465    /** Internal send FIFO queue */
     
    13768    uint8_t                     Alignment[2];
    13869
     70    /** The read queue. */
     71    uint8_t                     abReadBuf[256];
     72    /** Read buffer currently used. */
     73    size_t                      cbReadBufUsed;
     74    /** Current offset into the read buffer. */
     75    uint32_t                    offReadBuf;
     76
    13977    /** Read/write statistics */
    14078    STAMCOUNTER                 StatBytesRead;
    14179    STAMCOUNTER                 StatBytesWritten;
    142 #ifdef RT_OS_DARWIN
    143     /** The number of bytes we've dropped because the send queue
    144      * was full. */
    145     STAMCOUNTER                 StatSendOverflows;
    146 #endif
    14780} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
    14881
    149 
    150 /** Converts a pointer to DRVCHAR::ICharConnector to a PDRVHOSTSERIAL. */
    151 #define PDMICHAR_2_DRVHOSTSERIAL(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector)
    15282
    15383
     
    173103static DECLCALLBACK(int) drvHostSerialWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
    174104{
    175     PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
     105    PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector);
    176106    const uint8_t *pbBuffer = (const uint8_t *)pvBuf;
    177107
     
    184114
    185115        pThis->u8SendByte = pbBuffer[i];
    186         RTSemEventSignal(pThis->SendSem);
     116        RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
    187117        STAM_COUNTER_INC(&pThis->StatBytesWritten);
    188118    }
     
    190120}
    191121
     122
    192123static DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
    193124{
    194     PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
    195 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    196     struct termios *termiosSetup;
    197     int baud_rate;
    198 #elif defined(RT_OS_WINDOWS)
    199     LPDCB comSetup;
    200 #endif
    201 
    202     LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
    203 
    204 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    205     termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios));
    206 
    207     /* Enable receiver */
    208     termiosSetup->c_cflag |= (CLOCAL | CREAD);
    209 
    210     switch (Bps)
    211     {
    212         case 50:
    213             baud_rate = B50;
    214             break;
    215         case 75:
    216             baud_rate = B75;
    217             break;
    218         case 110:
    219             baud_rate = B110;
    220             break;
    221         case 134:
    222             baud_rate = B134;
    223             break;
    224         case 150:
    225             baud_rate = B150;
    226             break;
    227         case 200:
    228             baud_rate = B200;
    229             break;
    230         case 300:
    231             baud_rate = B300;
    232             break;
    233         case 600:
    234             baud_rate = B600;
    235             break;
    236         case 1200:
    237             baud_rate = B1200;
    238             break;
    239         case 1800:
    240             baud_rate = B1800;
    241             break;
    242         case 2400:
    243             baud_rate = B2400;
    244             break;
    245         case 4800:
    246             baud_rate = B4800;
    247             break;
    248         case 9600:
    249             baud_rate = B9600;
    250             break;
    251         case 19200:
    252             baud_rate = B19200;
    253             break;
    254         case 38400:
    255             baud_rate = B38400;
    256             break;
    257         case 57600:
    258             baud_rate = B57600;
    259             break;
    260         case 115200:
    261             baud_rate = B115200;
     125    PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector);
     126    RTSERIALPORTCFG Cfg;
     127
     128    Cfg.uBaudRate = Bps;
     129
     130    switch (chParity)
     131    {
     132        case 'E':
     133            Cfg.enmParity = RTSERIALPORTPARITY_EVEN;
     134            break;
     135        case 'O':
     136            Cfg.enmParity = RTSERIALPORTPARITY_ODD;
     137            break;
     138        case 'N':
     139            Cfg.enmParity = RTSERIALPORTPARITY_NONE;
    262140            break;
    263141        default:
    264 #ifdef RT_OS_LINUX
    265             struct serial_struct serialStruct;
    266             if (ioctl(RTFileToNative(pThis->hDeviceFile), TIOCGSERIAL, &serialStruct) != -1)
    267             {
    268                 serialStruct.custom_divisor = serialStruct.baud_base / Bps;
    269                 if (!serialStruct.custom_divisor)
    270                     serialStruct.custom_divisor = 1;
    271                 serialStruct.flags &= ~ASYNC_SPD_MASK;
    272                 serialStruct.flags |= ASYNC_SPD_CUST;
    273                 ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSSERIAL, &serialStruct);
    274                 baud_rate = B38400;
    275             }
    276             else
    277                 baud_rate = B9600;
    278 #else /* !RT_OS_LINUX */
    279             baud_rate = B9600;
    280 #endif /* !RT_OS_LINUX */
    281     }
    282 
    283     cfsetispeed(termiosSetup, baud_rate);
    284     cfsetospeed(termiosSetup, baud_rate);
    285 
    286     switch (chParity)
    287     {
    288         case 'E':
    289             termiosSetup->c_cflag |= PARENB;
    290             break;
    291         case 'O':
    292             termiosSetup->c_cflag |= (PARENB | PARODD);
    293             break;
    294         case 'N':
     142            AssertMsgFailed(("Unsupported parity setting %c\n", chParity)); /* Should not happen. */
     143            Cfg.enmParity = RTSERIALPORTPARITY_NONE;
     144    }
     145
     146    switch (cDataBits)
     147    {
     148        case 5:
     149            Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
     150            break;
     151        case 6:
     152            Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
     153            break;
     154        case 7:
     155            Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
     156            break;
     157        case 8:
     158            Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
    295159            break;
    296160        default:
    297             break;
    298     }
    299 
    300     switch (cDataBits)
    301     {
    302         case 5:
    303             termiosSetup->c_cflag |= CS5;
    304             break;
    305         case 6:
    306             termiosSetup->c_cflag |= CS6;
    307             break;
    308         case 7:
    309             termiosSetup->c_cflag |= CS7;
    310             break;
    311         case 8:
    312             termiosSetup->c_cflag |= CS8;
    313             break;
    314         default:
    315             break;
    316     }
    317 
    318     switch (cStopBits)
    319     {
    320         case 2:
    321             termiosSetup->c_cflag |= CSTOPB;
    322         default:
    323             break;
    324     }
    325 
    326     /* set serial port to raw input */
    327     termiosSetup->c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ECHOK | ISIG | IEXTEN);
    328 
    329     tcsetattr(RTFileToNative(pThis->hDeviceFile), TCSANOW, termiosSetup);
    330     RTMemTmpFree(termiosSetup);
    331 
    332 #ifdef RT_OS_LINUX
    333     /*
    334      * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
    335      * waiting in ioctl for a modem status change then 8250.c wrongly disables
    336      * modem irqs and so the monitor thread never gets released. The workaround
    337      * is to send a signal after each tcsetattr.
    338      */
    339     if (RT_LIKELY(pThis->pMonitorThread != NULL))
    340         RTThreadPoke(pThis->pMonitorThread->Thread);
    341 #endif
    342 
    343 #elif defined(RT_OS_WINDOWS)
    344     comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
    345 
    346     comSetup->DCBlength = sizeof(DCB);
    347 
    348     switch (Bps)
    349     {
    350         case 110:
    351             comSetup->BaudRate = CBR_110;
    352             break;
    353         case 300:
    354             comSetup->BaudRate = CBR_300;
    355             break;
    356         case 600:
    357             comSetup->BaudRate = CBR_600;
    358             break;
    359         case 1200:
    360             comSetup->BaudRate = CBR_1200;
    361             break;
    362         case 2400:
    363             comSetup->BaudRate = CBR_2400;
    364             break;
    365         case 4800:
    366             comSetup->BaudRate = CBR_4800;
    367             break;
    368         case 9600:
    369             comSetup->BaudRate = CBR_9600;
    370             break;
    371         case 14400:
    372             comSetup->BaudRate = CBR_14400;
    373             break;
    374         case 19200:
    375             comSetup->BaudRate = CBR_19200;
    376             break;
    377         case 38400:
    378             comSetup->BaudRate = CBR_38400;
    379             break;
    380         case 57600:
    381             comSetup->BaudRate = CBR_57600;
    382             break;
    383         case 115200:
    384             comSetup->BaudRate = CBR_115200;
    385             break;
    386         default:
    387             comSetup->BaudRate = CBR_9600;
    388     }
    389 
    390     comSetup->fBinary = TRUE;
    391     comSetup->fOutxCtsFlow = FALSE;
    392     comSetup->fOutxDsrFlow = FALSE;
    393     comSetup->fDtrControl = DTR_CONTROL_DISABLE;
    394     comSetup->fDsrSensitivity = FALSE;
    395     comSetup->fTXContinueOnXoff = TRUE;
    396     comSetup->fOutX = FALSE;
    397     comSetup->fInX = FALSE;
    398     comSetup->fErrorChar = FALSE;
    399     comSetup->fNull = FALSE;
    400     comSetup->fRtsControl = RTS_CONTROL_DISABLE;
    401     comSetup->fAbortOnError = FALSE;
    402     comSetup->wReserved = 0;
    403     comSetup->XonLim = 5;
    404     comSetup->XoffLim = 5;
    405     comSetup->ByteSize = cDataBits;
    406 
    407     switch (chParity)
    408     {
    409         case 'E':
    410             comSetup->Parity = EVENPARITY;
    411             break;
    412         case 'O':
    413             comSetup->Parity = ODDPARITY;
    414             break;
    415         case 'N':
    416             comSetup->Parity = NOPARITY;
    417             break;
    418         default:
    419             break;
    420     }
    421 
    422     switch (cStopBits)
    423     {
    424         case 1:
    425             comSetup->StopBits = ONESTOPBIT;
    426             break;
    427         case 2:
    428             comSetup->StopBits = TWOSTOPBITS;
    429             break;
    430         default:
    431             break;
    432     }
    433 
    434     comSetup->XonChar = 0;
    435     comSetup->XoffChar = 0;
    436     comSetup->ErrorChar = 0;
    437     comSetup->EofChar = 0;
    438     comSetup->EvtChar = 0;
    439 
    440     SetCommState(pThis->hDeviceFile, comSetup);
    441     RTMemTmpFree(comSetup);
    442 #endif /* RT_OS_WINDOWS */
    443 
    444     return VINF_SUCCESS;
     161            AssertMsgFailed(("Unsupported data bit count %u\n", cDataBits)); /* Should not happen. */
     162            Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
     163    }
     164
     165    if (cStopBits == 2)
     166        Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
     167    else
     168        Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
     169
     170    int rc = RTSerialPortCfgSet(pThis->hSerialPort, &Cfg, NULL);
     171    if (RT_FAILURE(rc))
     172        LogRelMax(10, ("HostSerial#%u: Failed to change settings to %u:%u%c%u (rc=%Rrc)\n",
     173                       pThis->pDrvIns->iInstance, Bps, cDataBits, chParity, cStopBits, rc));
     174    return rc;
    445175}
    446176
     
    448178
    449179/**
    450  * Send thread loop.
     180 * I/O thread loop.
    451181 *
    452182 * @returns VINF_SUCCESS.
     
    454184 * @param   pThread     The PDM thread data.
    455185 */
    456 static DECLCALLBACK(int) drvHostSerialSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     186static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    457187{
    458188    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
     
    461191        return VINF_SUCCESS;
    462192
    463 #ifdef RT_OS_WINDOWS
    464     /* Make sure that the halt event semaphore is reset. */
    465     DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
    466 
    467     HANDLE haWait[2];
    468     haWait[0] = pThis->hEventSend;
    469     haWait[1] = pThis->hHaltEventSem;
    470 #endif
    471 
    472193    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    473194    {
    474         int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT);
    475         AssertRCBreak(rc);
    476 
    477         /*
    478          * Write the character to the host device.
    479          */
    480         while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     195        if (pThis->offReadBuf < pThis->cbReadBufUsed)
    481196        {
    482             /* copy the send queue so we get a linear buffer with the maximal size. */
    483             uint8_t ch = pThis->u8SendByte;
    484 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    485 
    486             size_t cbWritten;
    487             rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
    488             if (rc == VERR_TRY_AGAIN)
    489                 cbWritten = 0;
    490             if (cbWritten < 1 && (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN))
     197            /* Try to send data to the guest. */
     198            size_t cbProcessed = pThis->cbReadBufUsed - pThis->offReadBuf;
     199            int rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, &pThis->abReadBuf[pThis->offReadBuf], &cbProcessed);
     200            if (RT_SUCCESS(rc))
    491201            {
    492                 /* ok, block till the device is ready for more (O_NONBLOCK) effect. */
    493                 rc = VINF_SUCCESS;
    494                 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     202                Assert(cbProcessed); Assert(cbProcessed <= pThis->cbReadBufUsed);
     203                pThis->offReadBuf += cbProcessed;
     204                STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
     205            }
     206            else if (rc != VERR_TIMEOUT)
     207                LogRelMax(10, ("HostSerial#%d: NotifyRead failed with %Rrc, expect errorneous device behavior.\n",
     208                               pDrvIns->iInstance, rc));
     209        }
     210
     211        uint32_t fEvtFlags = RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED | RTSERIALPORT_EVT_F_BREAK_DETECTED;
     212
     213        /* Wait until there is room again if there is anyting to send. */
     214        if (pThis->fSending)
     215            fEvtFlags |= RTSERIALPORT_EVT_F_DATA_TX;
     216
     217        /* Try to receive more if there is still room. */
     218        if (pThis->cbReadBufUsed < sizeof(pThis->abReadBuf))
     219            fEvtFlags |= RTSERIALPORT_EVT_F_DATA_RX;
     220
     221        uint32_t fEvtsRecv = 0;
     222        int rc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv,
     223                                     pThis->offReadBuf < pThis->cbReadBufUsed ? 100 : RT_INDEFINITE_WAIT);
     224        if (RT_SUCCESS(rc))
     225        {
     226            if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_TX)
     227            {
     228                Assert(pThis->fSending);
     229                size_t cbWritten = 0;
     230                uint8_t bSend = pThis->u8SendByte;
     231                rc = RTSerialPortWriteNB(pThis->hSerialPort, &bSend, 1, &cbWritten);
     232                if (RT_SUCCESS(rc))
    495233                {
    496                     /* wait */
    497                     fd_set WrSet;
    498                     FD_ZERO(&WrSet);
    499                     FD_SET(RTFileToNative(pThis->hDeviceFile), &WrSet);
    500                     fd_set XcptSet;
    501                     FD_ZERO(&XcptSet);
    502                     FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
    503 # ifdef DEBUG
    504                     uint64_t u64Now = RTTimeMilliTS();
    505 # endif
    506                     rc = select(RTFileToNative(pThis->hDeviceFile) + 1, NULL, &WrSet, &XcptSet, NULL);
    507                     /** @todo check rc? */
    508 
    509 # ifdef DEBUG
    510                     Log2(("select wait for %dms\n", RTTimeMilliTS() - u64Now));
    511 # endif
    512                     /* try write more */
    513                     rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
    514                     if (rc == VERR_TRY_AGAIN)
    515                         cbWritten = 0;
    516                     else if (RT_FAILURE(rc))
    517                         break;
    518                     else if (cbWritten >= 1)
    519                         break;
    520                     rc = VINF_SUCCESS;
    521                 } /* wait/write loop */
     234                    Assert(cbWritten == 1);
     235                    ASMAtomicXchgBool(&pThis->fSending, false);
     236                }
     237                else
     238                    LogRelMax(10, ("HostSerial#%d: Sending data failed even though the serial port is marked as writeable (rc=%Rrc)\n",
     239                                   pThis->pDrvIns->iInstance, rc));
    522240            }
    523241
    524 #elif defined(RT_OS_WINDOWS)
    525             /* perform an overlapped write operation. */
    526             DWORD cbWritten;
    527             memset(&pThis->overlappedSend, 0, sizeof(pThis->overlappedSend));
    528             pThis->overlappedSend.hEvent = pThis->hEventSend;
    529             if (!WriteFile(pThis->hDeviceFile, &ch, 1, &cbWritten, &pThis->overlappedSend))
     242            if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_RX)
    530243            {
    531                 dwRet = GetLastError();
    532                 if (dwRet == ERROR_IO_PENDING)
     244                /* Move all remaining data in the buffer to the front to make up as much room as possible. */
     245                if (pThis->offReadBuf)
    533246                {
    534                     /*
    535                      * write blocked, wait for completion or wakeup...
    536                      */
    537                     dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
    538                     if (dwRet != WAIT_OBJECT_0)
     247                    memmove(&pThis->abReadBuf[0], &pThis->abReadBuf[pThis->offReadBuf], pThis->cbReadBufUsed - pThis->offReadBuf);
     248                    pThis->cbReadBufUsed -= pThis->offReadBuf;
     249                    pThis->offReadBuf = 0;
     250                }
     251                size_t cbToRead = sizeof(pThis->abReadBuf) - pThis->cbReadBufUsed;
     252                size_t cbRead = 0;
     253                rc = RTSerialPortReadNB(pThis->hSerialPort, &pThis->abReadBuf[pThis->cbReadBufUsed], cbToRead, &cbRead);
     254                if (RT_SUCCESS(rc))
     255                    pThis->cbReadBufUsed += cbRead;
     256                else
     257                    LogRelMax(10, ("HostSerial#%d: Reading data failed even though the serial port is marked as readable (rc=%Rrc)\n",
     258                                   pThis->pDrvIns->iInstance, rc));
     259            }
     260
     261            if (fEvtsRecv & RTSERIALPORT_EVT_F_BREAK_DETECTED)
     262                pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort);
     263
     264            if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
     265            {
     266                /* The status lines have changed. Notify the device. */
     267                uint32_t fStsLines = 0;
     268                rc = RTSerialPortQueryStatusLines(pThis->hSerialPort, &fStsLines);
     269                if (RT_SUCCESS(rc))
     270                {
     271                    uint32_t fPdmStsLines = 0;
     272
     273                    if (fStsLines & RTSERIALPORT_STS_LINE_DCD)
     274                        fPdmStsLines |= PDMICHARPORT_STATUS_LINES_DCD;
     275                    if (fStsLines & RTSERIALPORT_STS_LINE_RI)
     276                        fPdmStsLines |= PDMICHARPORT_STATUS_LINES_RI;
     277                    if (fStsLines & RTSERIALPORT_STS_LINE_DSR)
     278                        fPdmStsLines |= PDMICHARPORT_STATUS_LINES_DSR;
     279                    if (fStsLines & RTSERIALPORT_STS_LINE_CTS)
     280                        fPdmStsLines |= PDMICHARPORT_STATUS_LINES_CTS;
     281
     282                    rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, fPdmStsLines);
     283                    if (RT_FAILURE(rc))
    539284                    {
    540                         AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
    541                         break;
     285                        /* Notifying device failed, continue but log it */
     286                        LogRelMax(10, ("HostSerial#%d: Notifying device about changed status lines failed with error %Rrc; continuing.\n",
     287                                       pDrvIns->iInstance, rc));
    542288                    }
    543289                }
    544290                else
    545                     rc = RTErrConvertFromWin32(dwRet);
     291                    LogRelMax(10, ("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
    546292            }
    547293
    548 #endif /* RT_OS_WINDOWS */
    549             if (RT_FAILURE(rc))
    550             {
    551                 LogRel(("HostSerial#%d: Serial Write failed with %Rrc; terminating send thread\n", pDrvIns->iInstance, rc));
    552                 return rc;
    553             }
    554             ASMAtomicXchgBool(&pThis->fSending, false);
    555             break;
    556         } /* write loop */
     294            if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED)
     295                LogRel(("HostSerial#%d: Status line monitoring failed at a lower level and is disabled\n", pDrvIns->iInstance));
     296        }
     297        else if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
     298        {
     299            /* Getting interrupted or running into a timeout are no error conditions. */
     300            rc = VINF_SUCCESS;
     301        }
    557302    }
    558303
    559304    return VINF_SUCCESS;
    560305}
     306
    561307
    562308/**
     
    567313 * @param     pThread     The send thread.
    568314 */
    569 static DECLCALLBACK(int) drvHostSerialWakeupSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     315static DECLCALLBACK(int) drvHostSerialWakeupIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    570316{
    571317    RT_NOREF(pThread);
    572318    PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    573     int rc;
    574 
    575     rc = RTSemEventSignal(pThis->SendSem);
    576     if (RT_FAILURE(rc))
    577         return rc;
    578 
    579 #ifdef RT_OS_WINDOWS
    580     if (!SetEvent(pThis->hHaltEventSem))
    581         return RTErrConvertFromWin32(GetLastError());
    582 #endif
    583 
    584     return VINF_SUCCESS;
    585 }
    586 
    587 /* -=-=-=-=- receive thread -=-=-=-=- */
    588 
    589 /**
    590  * Receive thread loop.
    591  *
    592  * This thread pushes data from the host serial device up the driver
    593  * chain toward the serial device.
    594  *
    595  * @returns VINF_SUCCESS.
    596  * @param   pDrvIns     PDM driver instance data.
    597  * @param   pThread     The PDM thread data.
    598  */
    599 static DECLCALLBACK(int) drvHostSerialRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    600 {
    601     PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    602     uint8_t abBuffer[256];
    603     uint8_t *pbBuffer = NULL;
    604     size_t cbRemaining = 0; /* start by reading host data */
    605     int rc = VINF_SUCCESS;
    606     int rcThread = VINF_SUCCESS;
    607 
    608     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    609         return VINF_SUCCESS;
    610 
    611 #ifdef RT_OS_WINDOWS
    612     /* Make sure that the halt event semaphore is reset. */
    613     DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
    614 
    615     HANDLE ahWait[2];
    616     ahWait[0] = pThis->hEventRecv;
    617     ahWait[1] = pThis->hHaltEventSem;
    618 #endif
    619 
    620     while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    621     {
    622         if (!cbRemaining)
    623         {
    624             /* Get a block of data from the host serial device. */
    625 
    626 #if defined(RT_OS_DARWIN) /* poll is broken on x86 darwin, returns POLLNVAL. */
    627             fd_set RdSet;
    628             FD_ZERO(&RdSet);
    629             FD_SET(RTFileToNative(pThis->hDeviceFileR), &RdSet);
    630             FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet);
    631             fd_set XcptSet;
    632             FD_ZERO(&XcptSet);
    633             FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
    634             FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet);
    635 # if 1 /* it seems like this select is blocking the write... */
    636             rc = select(RT_MAX(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR)) + 1,
    637                         &RdSet, NULL, &XcptSet, NULL);
    638 # else
    639             struct timeval tv = { 0, 1000 };
    640             rc = select(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR) + 1,
    641                         &RdSet, NULL, &XcptSet, &tv);
    642 # endif
    643             if (rc == -1)
    644             {
    645                 int err = errno;
    646                 rcThread = RTErrConvertFromErrno(err);
    647                 LogRel(("HostSerial#%d: select failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
    648                 break;
    649             }
    650 
    651             /* this might have changed in the meantime */
    652             if (pThread->enmState != PDMTHREADSTATE_RUNNING)
    653                 break;
    654             if (rc == 0)
    655                 continue;
    656 
    657             /* drain the wakeup pipe */
    658             size_t cbRead;
    659             if (   FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet)
    660                 || FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet))
    661             {
    662                 rc = RTPipeRead(pThis->hWakeupPipeR, abBuffer, 1, &cbRead);
    663                 if (RT_FAILURE(rc))
    664                 {
    665                     LogRel(("HostSerial#%d: draining the wakeup pipe failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
    666                     rcThread = rc;
    667                     break;
    668                 }
    669                 continue;
    670             }
    671 
    672             /* read data from the serial port. */
    673             rc = RTFileRead(pThis->hDeviceFileR, abBuffer, sizeof(abBuffer), &cbRead);
    674             if (RT_FAILURE(rc))
    675             {
    676                 LogRel(("HostSerial#%d: (1) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
    677                 rcThread = rc;
    678                 break;
    679             }
    680             cbRemaining = cbRead;
    681 
    682 #elif defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    683 
    684             size_t cbRead;
    685             struct pollfd aFDs[2];
    686             aFDs[0].fd      = RTFileToNative(pThis->hDeviceFile);
    687             aFDs[0].events  = POLLIN;
    688             aFDs[0].revents = 0;
    689             aFDs[1].fd      = RTPipeToNative(pThis->hWakeupPipeR);
    690             aFDs[1].events  = POLLIN | POLLERR | POLLHUP;
    691             aFDs[1].revents = 0;
    692             rc = poll(aFDs, RT_ELEMENTS(aFDs), -1);
    693             if (rc < 0)
    694             {
    695                 int err = errno;
    696                 if (err == EINTR)
    697                 {
    698                     /*
    699                      * EINTR errors should be harmless, even if they are not supposed to occur in our setup.
    700                      */
    701                     Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, err, strerror(err)));
    702                     RTThreadYield();
    703                     continue;
    704                 }
    705 
    706                 rcThread = RTErrConvertFromErrno(err);
    707                 LogRel(("HostSerial#%d: poll failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
    708                 break;
    709             }
    710             /* this might have changed in the meantime */
    711             if (pThread->enmState != PDMTHREADSTATE_RUNNING)
    712                 break;
    713             if (rc > 0 && aFDs[1].revents)
    714             {
    715                 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
    716                     break;
    717                 /* notification to terminate -- drain the pipe */
    718                 RTPipeRead(pThis->hWakeupPipeR, &abBuffer, 1, &cbRead);
    719                 continue;
    720             }
    721             rc = RTFileRead(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
    722             if (RT_FAILURE(rc))
    723             {
    724                 /* don't terminate worker thread when data unavailable */
    725                 if (rc == VERR_TRY_AGAIN)
    726                     continue;
    727 
    728                 LogRel(("HostSerial#%d: (2) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
    729                 rcThread = rc;
    730                 break;
    731             }
    732             cbRemaining = cbRead;
    733 
    734 #elif defined(RT_OS_WINDOWS)
    735 
    736             DWORD dwEventMask = 0;
    737             DWORD dwNumberOfBytesTransferred;
    738 
    739             memset(&pThis->overlappedRecv, 0, sizeof(pThis->overlappedRecv));
    740             pThis->overlappedRecv.hEvent = pThis->hEventRecv;
    741 
    742             if (!WaitCommEvent(pThis->hDeviceFile, &dwEventMask, &pThis->overlappedRecv))
    743             {
    744                 dwRet = GetLastError();
    745                 if (dwRet == ERROR_IO_PENDING)
    746                 {
    747                     dwRet = WaitForMultipleObjects(2, ahWait, FALSE, INFINITE);
    748                     if (dwRet != WAIT_OBJECT_0)
    749                     {
    750                         /* notification to terminate */
    751                         AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
    752                         break;
    753                     }
    754                 }
    755                 else
    756                 {
    757                     rcThread = RTErrConvertFromWin32(dwRet);
    758                     LogRel(("HostSerial#%d: Wait failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
    759                     break;
    760                 }
    761             }
    762             /* this might have changed in the meantime */
    763             if (pThread->enmState != PDMTHREADSTATE_RUNNING)
    764                 break;
    765 
    766             /* Check the event */
    767             if (dwEventMask & EV_RXCHAR)
    768             {
    769                 if (!ReadFile(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &pThis->overlappedRecv))
    770                 {
    771                     dwRet = GetLastError();
    772                     if (dwRet == ERROR_IO_PENDING)
    773                     {
    774                         if (GetOverlappedResult(pThis->hDeviceFile, &pThis->overlappedRecv, &dwNumberOfBytesTransferred, TRUE))
    775                             dwRet = NO_ERROR;
    776                         else
    777                             dwRet = GetLastError();
    778                     }
    779                     if (dwRet != NO_ERROR)
    780                     {
    781                         rcThread = RTErrConvertFromWin32(dwRet);
    782                         LogRel(("HostSerial#%d: Read failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
    783                         break;
    784                     }
    785                 }
    786                 cbRemaining = dwNumberOfBytesTransferred;
    787             }
    788             else if (dwEventMask & EV_BREAK)
    789             {
    790                 Log(("HostSerial#%d: Detected break\n"));
    791                 rc = pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort);
    792             }
    793             else
    794             {
    795                 /* The status lines have changed. Notify the device. */
    796                 DWORD dwNewStatusLinesState = 0;
    797                 uint32_t uNewStatusLinesState = 0;
    798 
    799                 /* Get the new state */
    800                 if (GetCommModemStatus(pThis->hDeviceFile, &dwNewStatusLinesState))
    801                 {
    802                     if (dwNewStatusLinesState & MS_RLSD_ON)
    803                         uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DCD;
    804                     if (dwNewStatusLinesState & MS_RING_ON)
    805                         uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_RI;
    806                     if (dwNewStatusLinesState & MS_DSR_ON)
    807                         uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DSR;
    808                     if (dwNewStatusLinesState & MS_CTS_ON)
    809                         uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_CTS;
    810                     rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, uNewStatusLinesState);
    811                     if (RT_FAILURE(rc))
    812                     {
    813                         /* Notifying device failed, continue but log it */
    814                         LogRel(("HostSerial#%d: Notifying device failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
    815                     }
    816                 }
    817                 else
    818                 {
    819                     /* Getting new state failed, continue but log it */
    820                     LogRel(("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError())));
    821                 }
    822             }
    823 #endif
    824 
    825             Log(("Read %d bytes.\n", cbRemaining));
    826             pbBuffer = abBuffer;
    827         }
    828         else
    829         {
    830             /* Send data to the guest. */
    831             size_t cbProcessed = cbRemaining;
    832             rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbBuffer, &cbProcessed);
    833             if (RT_SUCCESS(rc))
    834             {
    835                 Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
    836                 pbBuffer += cbProcessed;
    837                 cbRemaining -= cbProcessed;
    838                 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
    839             }
    840             else if (rc == VERR_TIMEOUT)
    841             {
    842                 /* Normal case, just means that the guest didn't accept a new
    843                  * character before the timeout elapsed. Just retry. */
    844                 rc = VINF_SUCCESS;
    845             }
    846             else
    847             {
    848                 LogRel(("HostSerial#%d: NotifyRead failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
    849                 rcThread = rc;
    850                 break;
    851             }
    852         }
    853     }
    854 
    855     return rcThread;
    856 }
    857 
    858 /**
    859  * Unblock the receive thread so it can respond to a state change.
    860  *
    861  * @returns a VBox status code.
    862  * @param     pDrvIns     The driver instance.
    863  * @param     pThread     The receive thread.
    864  */
    865 static DECLCALLBACK(int) drvHostSerialWakeupRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    866 {
    867     RT_NOREF(pThread);
    868     PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    869 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    870     size_t cbIgnored;
    871     return RTPipeWrite(pThis->hWakeupPipeW, "", 1, &cbIgnored);
    872 
    873 #elif defined(RT_OS_WINDOWS)
    874     if (!SetEvent(pThis->hHaltEventSem))
    875         return RTErrConvertFromWin32(GetLastError());
    876     return VINF_SUCCESS;
    877 #else
    878 # error adapt me!
    879 #endif
    880 }
    881 
    882 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    883 /* -=-=-=-=- Monitor thread -=-=-=-=- */
    884 
    885 /**
    886  * Monitor thread loop.
    887  *
    888  * This thread monitors the status lines and notifies the device
    889  * if they change.
    890  *
    891  * @returns VINF_SUCCESS.
    892  * @param   pDrvIns     PDM driver instance data.
    893  * @param   pThread     The PDM thread data.
    894  */
    895 static DECLCALLBACK(int) drvHostSerialMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    896 {
    897     PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    898     unsigned long const uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
    899 #ifdef RT_OS_LINUX
    900     bool fPoll = false;
    901 #endif
    902 
    903     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    904         return VINF_SUCCESS;
    905 
    906     do
    907     {
    908         unsigned int statusLines;
    909 
    910         /*
    911          * Get the status line state.
    912          */
    913         int rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &statusLines);
    914         if (rcPsx < 0)
    915         {
    916             PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
    917                                        N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
    918                                        pThis->pszDevicePath, RTErrConvertFromErrno(errno));
    919             break;
    920         }
    921 
    922         uint32_t newStatusLine = 0;
    923 
    924         if (statusLines & TIOCM_CAR)
    925             newStatusLine |= PDMICHARPORT_STATUS_LINES_DCD;
    926         if (statusLines & TIOCM_RNG)
    927             newStatusLine |= PDMICHARPORT_STATUS_LINES_RI;
    928         if (statusLines & TIOCM_DSR)
    929             newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR;
    930         if (statusLines & TIOCM_CTS)
    931             newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS;
    932         pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
    933 
    934         if (PDMTHREADSTATE_RUNNING != pThread->enmState)
    935             break;
    936 
    937 # ifdef RT_OS_LINUX
    938         /*
    939          * Wait for status line change.
    940          *
    941          * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
    942          * waiting in ioctl for a modem status change then 8250.c wrongly disables
    943          * modem irqs and so the monitor thread never gets released. The workaround
    944          * is to send a signal after each tcsetattr.
    945          *
    946          * TIOCMIWAIT doesn't work for the DSR line with TIOCM_DSR set
    947          * (see http://lxr.linux.no/#linux+v4.7/drivers/usb/class/cdc-acm.c#L949)
    948          * However as it is possible to query the line state we will not just clear
    949          * the TIOCM_DSR bit from the lines to check but resort to the polling
    950          * approach just like on other hosts.
    951          */
    952         if (!fPoll)
    953         {
    954             rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMIWAIT, uStatusLinesToCheck);
    955             if (rcPsx < 0 && errno != EINTR)
    956             {
    957                 LogRel(("Serial#%u: Failed to wait for status line change with rcPsx=%d errno=%d, switch to polling\n",
    958                         pDrvIns->iInstance, rcPsx, errno));
    959                 fPoll = true;
    960                 pThis->fStatusLines = statusLines;
    961             }
    962         }
    963         else
    964         {
    965             /* Poll for status line change. */
    966             if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
    967                 PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
    968             pThis->fStatusLines = statusLines;
    969         }
    970 # else
    971         /* Poll for status line change. */
    972         if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
    973             PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
    974         pThis->fStatusLines = statusLines;
    975 # endif
    976     } while (PDMTHREADSTATE_RUNNING == pThread->enmState);
    977 
    978     return VINF_SUCCESS;
    979 }
    980 
    981 /**
    982  * Unblock the monitor thread so it can respond to a state change.
    983  * We need to execute this code exactly once during initialization.
    984  * But we don't want to block --- therefore this dedicated thread.
    985  *
    986  * @returns a VBox status code.
    987  * @param     pDrvIns     The driver instance.
    988  * @param     pThread     The send thread.
    989  */
    990 static DECLCALLBACK(int) drvHostSerialWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    991 {
    992 # ifdef RT_OS_LINUX
    993     PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
    994     int rc = VINF_SUCCESS;
    995 
    996     rc = RTThreadPoke(pThread->Thread);
    997     if (RT_FAILURE(rc))
    998         PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
    999                                     N_("Suspending serial monitor thread failed for serial device '%s' (%Rrc). The shutdown may take longer than expected"),
    1000                                     pThis->pszDevicePath, RTErrConvertFromErrno(rc));
    1001 
    1002 # else  /* !RT_OS_LINUX*/
    1003 
    1004     /* In polling mode there is nobody to wake up (PDMThread will cancel the sleep). */
    1005     NOREF(pDrvIns);
    1006     NOREF(pThread);
    1007 
    1008 # endif /* RT_OS_LINUX */
    1009 
    1010     return VINF_SUCCESS;
    1011 }
    1012 #endif /* RT_OS_LINUX || RT_OS_DARWIN || RT_OS_SOLARIS */
     319
     320    return RTSerialPortEvtPollInterrupt(pThis->hSerialPort);;
     321}
     322
    1013323
    1014324/**
     
    1017327 * @returns VBox status code
    1018328 * @param pInterface        Pointer to the interface structure.
    1019  * @param RequestToSend     Set to true if this control line should be made active.
    1020  * @param DataTerminalReady Set to true if this control line should be made active.
    1021  */
    1022 static DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool RequestToSend, bool DataTerminalReady)
    1023 {
    1024     PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
    1025 
    1026 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1027     int modemStateSet = 0;
    1028     int modemStateClear = 0;
    1029 
    1030     if (RequestToSend)
    1031         modemStateSet |= TIOCM_RTS;
     329 * @param fRts              Set to true if this control line should be made active.
     330 * @param fDtr              Set to true if this control line should be made active.
     331 */
     332static DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool fRts, bool fDtr)
     333{
     334    PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector);
     335
     336    uint32_t fClear = 0;
     337    uint32_t fSet = 0;
     338
     339    if (fRts)
     340        fSet |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
    1032341    else
    1033         modemStateClear |= TIOCM_RTS;
    1034 
    1035     if (DataTerminalReady)
    1036         modemStateSet |= TIOCM_DTR;
     342        fClear |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
     343
     344    if (fDtr)
     345        fSet |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
    1037346    else
    1038         modemStateClear |= TIOCM_DTR;
    1039 
    1040     if (modemStateSet)
    1041         ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIS, &modemStateSet);
    1042 
    1043     if (modemStateClear)
    1044         ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIC, &modemStateClear);
    1045 
    1046 #elif defined(RT_OS_WINDOWS)
    1047     if (RequestToSend)
    1048         EscapeCommFunction(pThis->hDeviceFile, SETRTS);
    1049     else
    1050         EscapeCommFunction(pThis->hDeviceFile, CLRRTS);
    1051 
    1052     if (DataTerminalReady)
    1053         EscapeCommFunction(pThis->hDeviceFile, SETDTR);
    1054     else
    1055         EscapeCommFunction(pThis->hDeviceFile, CLRDTR);
    1056 
    1057 #endif
    1058 
    1059     return VINF_SUCCESS;
    1060 }
     347        fClear |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
     348
     349    return RTSerialPortChgStatusLines(pThis->hSerialPort, fClear, fSet);
     350}
     351
    1061352
    1062353/**
     
    1070361static DECLCALLBACK(int) drvHostSerialSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak)
    1071362{
    1072     PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
    1073 
    1074 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1075     if (fBreak)
    1076         ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSBRK);
    1077     else
    1078         ioctl(RTFileToNative(pThis->hDeviceFile), TIOCCBRK);
    1079 
    1080 #elif defined(RT_OS_WINDOWS)
    1081     if (fBreak)
    1082         SetCommBreak(pThis->hDeviceFile);
    1083     else
    1084         ClearCommBreak(pThis->hDeviceFile);
    1085 #endif
    1086 
    1087     return VINF_SUCCESS;
    1088 }
     363    PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector);
     364
     365    return RTSerialPortChgBreakCondition(pThis->hSerialPort, fBreak);
     366}
     367
    1089368
    1090369/* -=-=-=-=- driver interface -=-=-=-=- */
     
    1104383    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
    1105384
    1106     /* Empty the send queue */
    1107     if (pThis->SendSem != NIL_RTSEMEVENT)
    1108     {
    1109         RTSemEventDestroy(pThis->SendSem);
    1110         pThis->SendSem = NIL_RTSEMEVENT;
    1111     }
    1112 
    1113 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1114 
    1115     int rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc);
    1116     pThis->hWakeupPipeW = NIL_RTPIPE;
    1117     rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc);
    1118     pThis->hWakeupPipeR = NIL_RTPIPE;
    1119 
    1120 # if defined(RT_OS_DARWIN)
    1121     if (pThis->hDeviceFileR != NIL_RTFILE)
    1122     {
    1123         if (pThis->hDeviceFileR != pThis->hDeviceFile)
    1124         {
    1125             rc = RTFileClose(pThis->hDeviceFileR);
    1126             AssertRC(rc);
    1127         }
    1128         pThis->hDeviceFileR = NIL_RTFILE;
    1129     }
    1130 # endif
    1131     if (pThis->hDeviceFile != NIL_RTFILE)
    1132     {
    1133         rc = RTFileClose(pThis->hDeviceFile); AssertRC(rc);
    1134         pThis->hDeviceFile = NIL_RTFILE;
    1135     }
    1136 
    1137 #elif defined(RT_OS_WINDOWS)
    1138     CloseHandle(pThis->hEventRecv);
    1139     CloseHandle(pThis->hEventSend);
    1140     CancelIo(pThis->hDeviceFile);
    1141     CloseHandle(pThis->hDeviceFile);
    1142 
    1143 #endif
     385    if (pThis->hSerialPort != NIL_RTSERIALPORT)
     386    {
     387        RTSerialPortClose(pThis->hSerialPort);
     388        pThis->hSerialPort = NIL_RTSERIALPORT;
     389    }
    1144390
    1145391    if (pThis->pszDevicePath)
     
    1149395    }
    1150396}
     397
    1151398
    1152399/**
     
    1165412     * Init basic data members and interfaces.
    1166413     */
    1167 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1168     pThis->hDeviceFile  = NIL_RTFILE;
    1169 # ifdef RT_OS_DARWIN
    1170     pThis->hDeviceFileR = NIL_RTFILE;
    1171 # endif
    1172     pThis->hWakeupPipeR = NIL_RTPIPE;
    1173     pThis->hWakeupPipeW = NIL_RTPIPE;
    1174 #elif defined(RT_OS_WINDOWS)
    1175     pThis->hEventRecv  = INVALID_HANDLE_VALUE;
    1176     pThis->hEventSend  = INVALID_HANDLE_VALUE;
    1177     pThis->hDeviceFile = INVALID_HANDLE_VALUE;
    1178 #endif
    1179     pThis->SendSem     = NIL_RTSEMEVENT;
     414    pThis->hSerialPort   = NIL_RTSERIALPORT;
     415    pThis->offReadBuf    = 0;
     416    pThis->cbReadBufUsed = 0;
    1180417    /* IBase. */
    1181418    pDrvIns->IBase.pfnQueryInterface        = drvHostSerialQueryInterface;
     
    1200437     * Open the device
    1201438     */
    1202 #ifdef RT_OS_WINDOWS
    1203 
    1204     pThis->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
    1205     AssertReturn(pThis->hHaltEventSem != NULL, VERR_NO_MEMORY);
    1206 
    1207     pThis->hEventRecv = CreateEvent(NULL, FALSE, FALSE, NULL);
    1208     AssertReturn(pThis->hEventRecv != NULL, VERR_NO_MEMORY);
    1209 
    1210     pThis->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL);
    1211     AssertReturn(pThis->hEventSend != NULL, VERR_NO_MEMORY);
    1212 
    1213     HANDLE hFile = CreateFile(pThis->pszDevicePath,
    1214                               GENERIC_READ | GENERIC_WRITE,
    1215                               0, // must be opened with exclusive access
    1216                               NULL, // no SECURITY_ATTRIBUTES structure
    1217                               OPEN_EXISTING, // must use OPEN_EXISTING
    1218                               FILE_FLAG_OVERLAPPED, // overlapped I/O
    1219                               NULL); // no template file
    1220     if (hFile == INVALID_HANDLE_VALUE)
    1221         rc = RTErrConvertFromWin32(GetLastError());
    1222     else
    1223     {
    1224         pThis->hDeviceFile = hFile;
    1225         /* for overlapped read */
    1226         if (!SetCommMask(hFile, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING | EV_RLSD))
    1227         {
    1228             LogRel(("HostSerial#%d: SetCommMask failed with error %d.\n", pDrvIns->iInstance, GetLastError()));
    1229             return VERR_FILE_IO_ERROR;
    1230         }
    1231         rc = VINF_SUCCESS;
    1232     }
    1233 
    1234 #else /* !RT_OS_WINDOWS */
    1235 
    1236     uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
    1237 # ifdef RT_OS_LINUX
    1238     /* This seems to be necessary on some Linux hosts, otherwise we hang here forever. */
    1239     fOpen |= RTFILE_O_NON_BLOCK;
    1240 # endif
    1241     rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen);
    1242 # ifdef RT_OS_LINUX
    1243     /* RTFILE_O_NON_BLOCK not supported? */
    1244     if (rc == VERR_INVALID_PARAMETER)
    1245         rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen & ~RTFILE_O_NON_BLOCK);
    1246 # endif
    1247 # ifdef RT_OS_DARWIN
    1248     if (RT_SUCCESS(rc))
    1249         rc = RTFileOpen(&pThis->hDeviceFileR, pThis->pszDevicePath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    1250 # endif
    1251 
    1252 
    1253 #endif /* !RT_OS_WINDOWS */
    1254 
     439    uint32_t fOpenFlags =   RTSERIALPORT_OPEN_F_READ
     440                          | RTSERIALPORT_OPEN_F_WRITE
     441                          | RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING
     442                          | RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION;
     443    rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
    1255444    if (RT_FAILURE(rc))
    1256445    {
     
    1277466    }
    1278467
    1279     /* Set to non blocking I/O */
    1280 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1281 
    1282     fcntl(RTFileToNative(pThis->hDeviceFile), F_SETFL, O_NONBLOCK);
    1283 # ifdef RT_OS_DARWIN
    1284     fcntl(RTFileToNative(pThis->hDeviceFileR), F_SETFL, O_NONBLOCK);
    1285 # endif
    1286     rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/);
    1287     AssertRCReturn(rc, rc);
    1288 
    1289 #elif defined(RT_OS_WINDOWS)
    1290 
    1291     /* Set the COMMTIMEOUTS to get non blocking I/O */
    1292     COMMTIMEOUTS comTimeout;
    1293 
    1294     comTimeout.ReadIntervalTimeout         = MAXDWORD;
    1295     comTimeout.ReadTotalTimeoutMultiplier  = 0;
    1296     comTimeout.ReadTotalTimeoutConstant    = 0;
    1297     comTimeout.WriteTotalTimeoutMultiplier = 0;
    1298     comTimeout.WriteTotalTimeoutConstant   = 0;
    1299 
    1300     SetCommTimeouts(pThis->hDeviceFile, &comTimeout);
    1301 
    1302 #endif
    1303 
    1304468    /*
    1305469     * Get the ICharPort interface of the above driver/device.
     
    1310474
    1311475    /*
    1312      * Create the receive, send and monitor threads plus the related send semaphore.
     476     * Create the I/O thread.
    1313477     */
    1314     rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pRecvThread, pThis, drvHostSerialRecvThread, drvHostSerialWakeupRecvThread, 0, RTTHREADTYPE_IO, "SerRecv");
     478    rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pIoThrd, pThis, drvHostSerialIoThread, drvHostSerialWakeupIoThread, 0, RTTHREADTYPE_IO, "SerIo");
    1315479    if (RT_FAILURE(rc))
    1316         return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
    1317 
    1318     rc = RTSemEventCreate(&pThis->SendSem);
    1319     AssertRC(rc);
    1320 
    1321     rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pSendThread, pThis, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "SerSend");
    1322     if (RT_FAILURE(rc))
    1323         return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
    1324 
    1325 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
    1326     /* Linux & darwin needs a separate thread which monitors the status lines. */
    1327     int rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &pThis->fStatusLines);
    1328     if (!rcPsx)
    1329     {
    1330         rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostSerialMonitorThread, drvHostSerialWakeupMonitorThread, 0, RTTHREADTYPE_IO, "SerMon");
    1331         if (RT_FAILURE(rc))
    1332             return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create monitor thread"), pDrvIns->iInstance);
    1333     }
    1334     else
    1335     {
    1336         /* TIOCMGET is not supported for pseudo terminals so just silently skip it. */
    1337         if (errno != ENOTTY)
    1338             PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
    1339                                        N_("Trying to get the status lines state failed for serial host device '%s' (%Rrc). The device will not work properly"),
    1340                                        pThis->pszDevicePath, RTErrConvertFromErrno(errno));
    1341     }
    1342 #endif
     480        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create I/O thread"), pDrvIns->iInstance);
    1343481
    1344482    /*
     
    1347485    PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written",         "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
    1348486    PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead,       STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read",            "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
    1349 #ifdef RT_OS_DARWIN /* new Write code, not darwin specific. */
    1350     PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSendOverflows,   STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes overflowed",      "/Devices/HostSerial%d/SendOverflow", pDrvIns->iInstance);
    1351 #endif
    1352487
    1353488    return VINF_SUCCESS;
     
    1367502    /* szR0Mod */
    1368503    "",
    1369 /* pszDescription */
     504    /* pszDescription */
    1370505    "Host serial driver.",
    1371506    /* fFlags */
Note: See TracChangeset for help on using the changeset viewer.

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