DrvHostSerial.cpp revision bb56e9b73a923e975bc18bea69639b4c07e32f60
7df95d48add893eab9003d793e18c099e126edf9vboxsync/* $Id$ */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** @file
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * VBox stream I/O devices: Host serial driver
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2012 Oracle Corporation
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * available from http://www.virtualbox.org. This file is free software;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*******************************************************************************
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync* Header Files *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync*******************************************************************************/
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdm.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <VBox/err.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <VBox/log.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <iprt/asm.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <iprt/assert.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <iprt/file.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/mem.h>
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync#include <iprt/pipe.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/semaphore.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/uuid.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync# include <errno.h>
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync# ifdef RT_OS_SOLARIS
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync# include <sys/termios.h>
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync# else
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync# include <termios.h>
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync# endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <sys/types.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <fcntl.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <string.h>
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync# include <unistd.h>
ccc1001951ecd639b15b3034260c6012423349b3vboxsync# ifdef RT_OS_DARWIN
ccc1001951ecd639b15b3034260c6012423349b3vboxsync# include <sys/select.h>
ccc1001951ecd639b15b3034260c6012423349b3vboxsync# else
ccc1001951ecd639b15b3034260c6012423349b3vboxsync# include <sys/poll.h>
ccc1001951ecd639b15b3034260c6012423349b3vboxsync# endif
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync# include <sys/ioctl.h>
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync# include <pthread.h>
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# ifdef RT_OS_LINUX
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync/*
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * TIOCM_LOOP is not defined in the above header files for some reason but in asm/termios.h.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * But inclusion of this file however leads to compilation errors because of redefinition of some
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * structs. That's why it is defined here until a better solution is found.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# ifndef TIOCM_LOOP
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# define TIOCM_LOOP 0x8000
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync/* For linux custom baudrate code we also need serial_struct */
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync# include <linux/serial.h>
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif /* linux */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#elif defined(RT_OS_WINDOWS)
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# include <Windows.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include "VBoxDD.h"
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*******************************************************************************
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync* Structures and Typedefs *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync*******************************************************************************/
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Char driver instance data.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync *
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @implements PDMICHARCONNECTOR
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsynctypedef struct DRVHOSTSERIAL
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Pointer to the driver instance structure. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PPDMDRVINS pDrvIns;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Pointer to the char port interface of the driver/device above us. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PPDMICHARPORT pDrvCharPort;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Our char interface. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync PDMICHARCONNECTOR ICharConnector;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** Receive thread. */
9f9f83ee5948916d644046a79836873db40bfc88vboxsync PPDMTHREAD pRecvThread;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** Send thread. */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PPDMTHREAD pSendThread;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync /** Status lines monitor thread. */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync PPDMTHREAD pMonitorThread;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** Send event semaphore */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync RTSEMEVENT SendSem;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** the device path */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync char *pszDevicePath;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** the device handle */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTFILE hDeviceFile;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
a9e040e11af94d3457b824f2942d11375f16f598vboxsync /** The device handle used for reading.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Used to prevent the read select from blocking the writes. */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTFILE hDeviceFileR;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The read end of the control pipe */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTPIPE hWakeupPipeR;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The write end of the control pipe */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTPIPE hWakeupPipeW;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# ifndef RT_OS_LINUX
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync /** The current line status.
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync * Used by the polling version of drvHostSerialMonitorThread. */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync int fStatusLines;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
c808a168c13130bbd814115581cd91e6fe28472bvboxsync#elif defined(RT_OS_WINDOWS)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** the device handle */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE hDeviceFile;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The event semaphore for waking up the receive thread */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE hHaltEventSem;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The event semaphore for overlapped receiving */
9f9f83ee5948916d644046a79836873db40bfc88vboxsync HANDLE hEventRecv;
9f9f83ee5948916d644046a79836873db40bfc88vboxsync /** For overlapped receiving */
9f9f83ee5948916d644046a79836873db40bfc88vboxsync OVERLAPPED overlappedRecv;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The event semaphore for overlapped sending */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE hEventSend;
9f9f83ee5948916d644046a79836873db40bfc88vboxsync /** For overlapped sending */
9f9f83ee5948916d644046a79836873db40bfc88vboxsync OVERLAPPED overlappedSend;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Internal send FIFO queue */
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync uint8_t volatile u8SendByte;
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync bool volatile fSending;
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync uint8_t Alignment[2];
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Read/write statistics */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync STAMCOUNTER StatBytesRead;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync STAMCOUNTER StatBytesWritten;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#ifdef RT_OS_DARWIN
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /** The number of bytes we've dropped because the send queue
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync * was full. */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync STAMCOUNTER StatSendOverflows;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/** Converts a pointer to DRVCHAR::ICharConnector to a PDRVHOSTSERIAL. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync#define PDMICHAR_2_DRVHOSTSERIAL(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- IBase -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARCONNECTOR, &pThis->ICharConnector);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return NULL;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/* -=-=-=-=- ICharConnector -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/** @copydoc PDMICHARCONNECTOR::pfnWrite */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvHostSerialWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync const uint8_t *pbBuffer = (const uint8_t *)pvBuf;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync for (uint32_t i = 0; i < cbWrite; i++)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync if (ASMAtomicXchgBool(&pThis->fSending, true))
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync return VERR_BUFFER_OVERFLOW;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync pThis->u8SendByte = pbBuffer[i];
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync RTSemEventSignal(pThis->SendSem);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync STAM_COUNTER_INC(&pThis->StatBytesWritten);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync struct termios *termiosSetup;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync int baud_rate;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#elif defined(RT_OS_WINDOWS)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync LPDCB comSetup;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Enable receiver */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= (CLOCAL | CREAD);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (Bps)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 50:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B50;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 75:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B75;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 110:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B110;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 134:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B134;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 150:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B150;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 300:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B300;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 600:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 1200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B1200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 1800:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B1800;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 2400:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B2400;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 4800:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B4800;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 9600:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B9600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 19200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B19200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 38400:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B38400;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 57600:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B57600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 115200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B115200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync#ifdef RT_OS_LINUX
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync struct serial_struct serialStruct;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync if (ioctl(RTFileToNative(pThis->hDeviceFile), TIOCGSERIAL, &serialStruct) != -1)
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync {
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync serialStruct.custom_divisor = serialStruct.baud_base / Bps;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync if (!serialStruct.custom_divisor)
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync serialStruct.custom_divisor = 1;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync serialStruct.flags &= ~ASYNC_SPD_MASK;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync serialStruct.flags |= ASYNC_SPD_CUST;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSSERIAL, &serialStruct);
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync baud_rate = B38400;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync }
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync else
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync baud_rate = B9600;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync#else /* !RT_OS_LINUX */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B9600;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync#endif /* !RT_OS_LINUX */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync cfsetispeed(termiosSetup, baud_rate);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync cfsetospeed(termiosSetup, baud_rate);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (chParity)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 'E':
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= PARENB;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 'O':
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= (PARENB | PARODD);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 'N':
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (cDataBits)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 5:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= CS5;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 6:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= CS6;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 7:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= CS7;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 8:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= CS8;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (cStopBits)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 2:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_cflag |= CSTOPB;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* set serial port to raw input */
d3ee346250c69f7a5640458e7b6f17705e5ccf79vboxsync termiosSetup->c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ECHOK | ISIG | IEXTEN);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync tcsetattr(RTFileToNative(pThis->hDeviceFile), TCSANOW, termiosSetup);
dcba8de9fb9216170ee6740b57a51b3c8f2a55fcvboxsync RTMemTmpFree(termiosSetup);
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync#ifdef RT_OS_LINUX
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync /*
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * waiting in ioctl for a modem status change then 8250.c wrongly disables
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * modem irqs and so the monitor thread never gets released. The workaround
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * is to send a signal after each tcsetattr.
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync */
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync RTThreadPoke(pThis->pMonitorThread->Thread);
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync#endif
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#elif defined(RT_OS_WINDOWS)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->DCBlength = sizeof(DCB);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (Bps)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 110:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_110;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 300:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_300;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 600:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 1200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_1200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 2400:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_2400;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 4800:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_4800;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 9600:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_9600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 14400:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_14400;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 19200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_19200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 38400:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_38400;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 57600:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_57600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 115200:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_115200;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->BaudRate = CBR_9600;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fBinary = TRUE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fOutxCtsFlow = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fOutxDsrFlow = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fDtrControl = DTR_CONTROL_DISABLE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fDsrSensitivity = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fTXContinueOnXoff = TRUE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fOutX = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fInX = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fErrorChar = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fNull = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fRtsControl = RTS_CONTROL_DISABLE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->fAbortOnError = FALSE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->wReserved = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->XonLim = 5;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->XoffLim = 5;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->ByteSize = cDataBits;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (chParity)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 'E':
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->Parity = EVENPARITY;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 'O':
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->Parity = ODDPARITY;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 'N':
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->Parity = NOPARITY;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync switch (cStopBits)
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 1:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->StopBits = ONESTOPBIT;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case 2:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->StopBits = TWOSTOPBITS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->XonChar = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->XoffChar = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->ErrorChar = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->EofChar = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->EvtChar = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync SetCommState(pThis->hDeviceFile, comSetup);
dcba8de9fb9216170ee6740b57a51b3c8f2a55fcvboxsync RTMemTmpFree(comSetup);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif /* RT_OS_WINDOWS */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- receive thread -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Send thread loop.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @returns VINF_SUCCESS.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param ThreadSelf Thread handle to this thread.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param pvUser User argument.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsyncstatic DECLCALLBACK(int) drvHostSerialSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
a9e040e11af94d3457b824f2942d11375f16f598vboxsync /* Make sure that the halt event semaphore is reset. */
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE haWait[2];
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync haWait[0] = pThis->hEventSend;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync haWait[1] = pThis->hHaltEventSem;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Write the character to the host device.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* copy the send queue so we get a linear buffer with the maximal size. */
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync uint8_t ch = pThis->u8SendByte;
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync size_t cbWritten;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (rc == VERR_TRY_AGAIN)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync cbWritten = 0;
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync if (cbWritten < 1 && (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN))
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* ok, block till the device is ready for more (O_NONBLOCK) effect. */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = VINF_SUCCESS;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* wait */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync fd_set WrSet;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync FD_ZERO(&WrSet);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync FD_SET(RTFileToNative(pThis->hDeviceFile), &WrSet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync fd_set XcptSet;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync FD_ZERO(&XcptSet);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync# ifdef DEBUG
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync uint64_t u64Now = RTTimeMilliTS();
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync# endif
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = select(RTFileToNative(pThis->hDeviceFile) + 1, NULL, &WrSet, &XcptSet, NULL);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /** @todo check rc? */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync# ifdef DEBUG
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync Log2(("select wait for %dms\n", RTTimeMilliTS() - u64Now));
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync# endif
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* try write more */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (rc == VERR_TRY_AGAIN)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync cbWritten = 0;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync else if (RT_FAILURE(rc))
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync else if (cbWritten >= 1)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = VINF_SUCCESS;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync } /* wait/write loop */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync#elif defined(RT_OS_WINDOWS)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* perform an overlapped write operation. */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync DWORD cbWritten;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync memset(&pThis->overlappedSend, 0, sizeof(pThis->overlappedSend));
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync pThis->overlappedSend.hEvent = pThis->hEventSend;
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync if (!WriteFile(pThis->hDeviceFile, &ch, 1, &cbWritten, &pThis->overlappedSend))
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync dwRet = GetLastError();
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (dwRet == ERROR_IO_PENDING)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /*
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync * write blocked, wait for completion or wakeup...
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (dwRet != WAIT_OBJECT_0)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync else
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = RTErrConvertFromWin32(dwRet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync#endif /* RT_OS_WINDOWS */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (RT_FAILURE(rc))
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync LogRel(("HostSerial#%d: Serial Write failed with %Rrc; terminating send thread\n", pDrvIns->iInstance, rc));
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync return rc;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync ASMAtomicXchgBool(&pThis->fSending, false);
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync } /* write loop */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync/**
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * Unblock the send thread so it can respond to a state change.
b8939a8db837f27574e06c82474888bdd058ce17vboxsync *
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * @returns a VBox status code.
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * @param pDrvIns The driver instance.
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * @param pThread The send thread.
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync */
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsyncstatic DECLCALLBACK(int) drvHostSerialWakeupSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD /*pThread*/)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int rc;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = RTSemEventSignal(pThis->SendSem);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (RT_FAILURE(rc))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return rc;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!SetEvent(pThis->hHaltEventSem))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return RTErrConvertFromWin32(GetLastError());
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- receive thread -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Receive thread loop.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * This thread pushes data from the host serial device up the driver
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * chain toward the serial device.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @returns VINF_SUCCESS.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param ThreadSelf Thread handle to this thread.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param pvUser User argument.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
9f9f83ee5948916d644046a79836873db40bfc88vboxsyncstatic DECLCALLBACK(int) drvHostSerialRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync uint8_t abBuffer[256];
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync uint8_t *pbBuffer = NULL;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync size_t cbRemaining = 0; /* start by reading host data */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync int rc = VINF_SUCCESS;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync int rcThread = VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
a9e040e11af94d3457b824f2942d11375f16f598vboxsync /* Make sure that the halt event semaphore is reset. */
b5523a351ce3a0829df2421672ef4bf1481970bcvboxsync DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync HANDLE ahWait[2];
5fced272b977bf1c44cfc74cb94b96346a0a34a5vboxsync ahWait[0] = pThis->hEventRecv;
5fced272b977bf1c44cfc74cb94b96346a0a34a5vboxsync ahWait[1] = pThis->hHaltEventSem;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (!cbRemaining)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Get a block of data from the host serial device. */
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync#if defined(RT_OS_DARWIN) /* poll is broken on x86 darwin, returns POLLNVAL. */
7df95d48add893eab9003d793e18c099e126edf9vboxsync fd_set RdSet;
7df95d48add893eab9003d793e18c099e126edf9vboxsync FD_ZERO(&RdSet);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync FD_SET(RTFileToNative(pThis->hDeviceFileR), &RdSet);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet);
7df95d48add893eab9003d793e18c099e126edf9vboxsync fd_set XcptSet;
7df95d48add893eab9003d793e18c099e126edf9vboxsync FD_ZERO(&XcptSet);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync# if 1 /* it seems like this select is blocking the write... */
cae3b8810c39392e70dfb12b951431018a80fcbavboxsync rc = select(RT_MAX(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR)) + 1,
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync &RdSet, NULL, &XcptSet, NULL);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync# else
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync struct timeval tv = { 0, 1000 };
cae3b8810c39392e70dfb12b951431018a80fcbavboxsync rc = select(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR) + 1,
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync &RdSet, NULL, &XcptSet, &tv);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync# endif
ccc1001951ecd639b15b3034260c6012423349b3vboxsync if (rc == -1)
ccc1001951ecd639b15b3034260c6012423349b3vboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync int err = errno;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = RTErrConvertFromErrno(err);
ccc1001951ecd639b15b3034260c6012423349b3vboxsync LogRel(("HostSerial#%d: select failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
ccc1001951ecd639b15b3034260c6012423349b3vboxsync break;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync }
ccc1001951ecd639b15b3034260c6012423349b3vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync /* this might have changed in the meantime */
ccc1001951ecd639b15b3034260c6012423349b3vboxsync if (pThread->enmState != PDMTHREADSTATE_RUNNING)
ccc1001951ecd639b15b3034260c6012423349b3vboxsync break;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync if (rc == 0)
ccc1001951ecd639b15b3034260c6012423349b3vboxsync continue;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync /* drain the wakeup pipe */
7df95d48add893eab9003d793e18c099e126edf9vboxsync size_t cbRead;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync if ( FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet)
cae3b8810c39392e70dfb12b951431018a80fcbavboxsync || FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet))
ccc1001951ecd639b15b3034260c6012423349b3vboxsync {
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTPipeRead(pThis->hWakeupPipeR, abBuffer, 1, &cbRead);
ccc1001951ecd639b15b3034260c6012423349b3vboxsync if (RT_FAILURE(rc))
ccc1001951ecd639b15b3034260c6012423349b3vboxsync {
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync LogRel(("HostSerial#%d: draining the wakeup pipe failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = rc;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync break;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync }
ccc1001951ecd639b15b3034260c6012423349b3vboxsync continue;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync }
ccc1001951ecd639b15b3034260c6012423349b3vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync /* read data from the serial port. */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileRead(pThis->hDeviceFileR, abBuffer, sizeof(abBuffer), &cbRead);
ccc1001951ecd639b15b3034260c6012423349b3vboxsync if (RT_FAILURE(rc))
ccc1001951ecd639b15b3034260c6012423349b3vboxsync {
2690c73e870741ed425524c68c11159c1e53d314vboxsync LogRel(("HostSerial#%d: (1) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = rc;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync break;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync }
ccc1001951ecd639b15b3034260c6012423349b3vboxsync cbRemaining = cbRead;
ccc1001951ecd639b15b3034260c6012423349b3vboxsync
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#elif defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync size_t cbRead;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync struct pollfd aFDs[2];
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync aFDs[0].fd = RTFileToNative(pThis->hDeviceFile);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].events = POLLIN;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].revents = 0;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync aFDs[1].fd = RTPipeToNative(pThis->hWakeupPipeR);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[1].events = POLLIN | POLLERR | POLLHUP;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[1].revents = 0;
e8337e527775f93549a93be513bd5b4b9d658569vboxsync rc = poll(aFDs, RT_ELEMENTS(aFDs), -1);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (rc < 0)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync int err = errno;
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync if (err == EINTR)
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync {
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync /*
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync * EINTR errors should be harmless, even if they are not supposed to occur in our setup.
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync */
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, err, strerror(err)));
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync RTThreadYield();
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync continue;
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync }
afb320af7168b3ee668e08ea03594f9c4b814a70vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = RTErrConvertFromErrno(err);
ccc1001951ecd639b15b3034260c6012423349b3vboxsync LogRel(("HostSerial#%d: poll failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* this might have changed in the meantime */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState != PDMTHREADSTATE_RUNNING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (rc > 0 && aFDs[1].revents)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* notification to terminate -- drain the pipe */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTPipeRead(pThis->hWakeupPipeR, &abBuffer, 1, &cbRead);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync continue;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileRead(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
2690c73e870741ed425524c68c11159c1e53d314vboxsync /* don't terminate worker thread when data unavailable */
2690c73e870741ed425524c68c11159c1e53d314vboxsync if (rc == VERR_TRY_AGAIN)
2690c73e870741ed425524c68c11159c1e53d314vboxsync continue;
2690c73e870741ed425524c68c11159c1e53d314vboxsync
2690c73e870741ed425524c68c11159c1e53d314vboxsync LogRel(("HostSerial#%d: (2) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = rc;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync cbRemaining = cbRead;
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#elif defined(RT_OS_WINDOWS)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD dwEventMask = 0;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD dwNumberOfBytesTransferred;
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync memset(&pThis->overlappedRecv, 0, sizeof(pThis->overlappedRecv));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->overlappedRecv.hEvent = pThis->hEventRecv;
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!WaitCommEvent(pThis->hDeviceFile, &dwEventMask, &pThis->overlappedRecv))
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync {
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync dwRet = GetLastError();
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet == ERROR_IO_PENDING)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync dwRet = WaitForMultipleObjects(2, ahWait, FALSE, INFINITE);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet != WAIT_OBJECT_0)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* notification to terminate */
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = RTErrConvertFromWin32(dwRet);
ccc1001951ecd639b15b3034260c6012423349b3vboxsync LogRel(("HostSerial#%d: Wait failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync break;
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync }
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* this might have changed in the meantime */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState != PDMTHREADSTATE_RUNNING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync /* Check the event */
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync if (dwEventMask & EV_RXCHAR)
243cc1785504c050523fbc933363759b63fc59f0vboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!ReadFile(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &pThis->overlappedRecv))
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = RTErrConvertFromWin32(GetLastError());
ccc1001951ecd639b15b3034260c6012423349b3vboxsync LogRel(("HostSerial#%d: Read failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync break;
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync }
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync cbRemaining = dwNumberOfBytesTransferred;
243cc1785504c050523fbc933363759b63fc59f0vboxsync }
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync else if (dwEventMask & EV_BREAK)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync {
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync Log(("HostSerial#%d: Detected break\n"));
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync rc = pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync }
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync else
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync {
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync /* The status lines have changed. Notify the device. */
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync DWORD dwNewStatusLinesState = 0;
bba55f1c73e5952282db3fbaf4c95580083e0306vboxsync uint32_t uNewStatusLinesState = 0;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync /* Get the new state */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (GetCommModemStatus(pThis->hDeviceFile, &dwNewStatusLinesState))
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync {
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync if (dwNewStatusLinesState & MS_RLSD_ON)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DCD;
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync if (dwNewStatusLinesState & MS_RING_ON)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_RI;
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync if (dwNewStatusLinesState & MS_DSR_ON)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DSR;
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync if (dwNewStatusLinesState & MS_CTS_ON)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_CTS;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, uNewStatusLinesState);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync {
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync /* Notifying device failed, continue but log it */
fe813b3594039ba864493438e78ee0e7132bc445vboxsync LogRel(("HostSerial#%d: Notifying device failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync }
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync }
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync else
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync {
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync /* Getting new state failed, continue but log it */
fe813b3594039ba864493438e78ee0e7132bc445vboxsync LogRel(("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError())));
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync }
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync }
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync Log(("Read %d bytes.\n", cbRemaining));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pbBuffer = abBuffer;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync else
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Send data to the guest. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync size_t cbProcessed = cbRemaining;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbBuffer, &cbProcessed);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_SUCCESS(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pbBuffer += cbProcessed;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync cbRemaining -= cbProcessed;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync else if (rc == VERR_TIMEOUT)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Normal case, just means that the guest didn't accept a new
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * character before the timeout elapsed. Just retry. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync rc = VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync else
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
fe813b3594039ba864493438e78ee0e7132bc445vboxsync LogRel(("HostSerial#%d: NotifyRead failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rcThread = rc;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
ccc1001951ecd639b15b3034260c6012423349b3vboxsync return rcThread;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync/**
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * Unblock the send thread so it can respond to a state change.
b8939a8db837f27574e06c82474888bdd058ce17vboxsync *
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * @returns a VBox status code.
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * @param pDrvIns The driver instance.
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * @param pThread The send thread.
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync */
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsyncstatic DECLCALLBACK(int) drvHostSerialWakeupRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD /*pThread*/)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync size_t cbIgnored;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync return RTPipeWrite(pThis->hWakeupPipeW, "", 1, &cbIgnored);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync
d3de369f8d66bc3c40cd338831bd5908c2f82d16vboxsync#elif defined(RT_OS_WINDOWS)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!SetEvent(pThis->hHaltEventSem))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return RTErrConvertFromWin32(GetLastError());
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync# error adapt me!
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync}
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync/* -=-=-=-=- Monitor thread -=-=-=-=- */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync/**
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * Monitor thread loop.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync *
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * This thread monitors the status lines and notifies the device
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * if they change.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync *
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @returns VINF_SUCCESS.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @param ThreadSelf Thread handle to this thread.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @param pvUser User argument.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsyncstatic DECLCALLBACK(int) drvHostSerialMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync int rc = VINF_SUCCESS;
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync unsigned long const uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync return VINF_SUCCESS;
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync do
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync {
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync unsigned int statusLines;
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync /*
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * Get the status line state.
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &statusLines);
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync if (rc < 0)
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync {
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync pThis->pszDevicePath, RTErrConvertFromErrno(errno));
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync break;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync }
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync uint32_t newStatusLine = 0;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_CAR)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_DCD;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_RNG)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_RI;
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync if (statusLines & TIOCM_DSR)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_CTS)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS;
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync if (PDMTHREADSTATE_RUNNING != pThread->enmState)
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync break;
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync# ifdef RT_OS_LINUX
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync /*
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * Wait for status line change.
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync *
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * waiting in ioctl for a modem status change then 8250.c wrongly disables
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * modem irqs and so the monitor thread never gets released. The workaround
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync * is to send a signal after each tcsetattr.
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMIWAIT, uStatusLinesToCheck);
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync# else
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync /* Poll for status line change. */
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync pThis->fStatusLines = statusLines;
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync# endif
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync }
1914c6bfdb6ec56deb381bdca7da860677d165eavboxsync while (PDMTHREADSTATE_RUNNING == pThread->enmState);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync return VINF_SUCCESS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync}
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync/**
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * Unblock the monitor thread so it can respond to a state change.
db3cb946a1e459bf2a3f3292f481093eb526ebc0vboxsync * We need to execute this code exactly once during initialization.
db3cb946a1e459bf2a3f3292f481093eb526ebc0vboxsync * But we don't want to block --- therefore this dedicated thread.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync *
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @returns a VBox status code.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @param pDrvIns The driver instance.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @param pThread The send thread.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsyncstatic DECLCALLBACK(int) drvHostSerialWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync{
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# ifdef RT_OS_LINUX
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync int rc = VINF_SUCCESS;
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync
7b5acbc782f6cd0d65b05c8afc90047f820e9938vboxsync rc = RTThreadPoke(pThread->Thread);
7b5acbc782f6cd0d65b05c8afc90047f820e9938vboxsync if (RT_FAILURE(rc))
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
0ff7152ccdcc57edca12c5f17b9699c66eeff975vboxsync N_("Suspending serial monitor thread failed for serial device '%s' (%Rrc). The shutdown may take longer than expected"),
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync pThis->pszDevicePath, RTErrConvertFromErrno(rc));
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# else /* !RT_OS_LINUX*/
7b5acbc782f6cd0d65b05c8afc90047f820e9938vboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync /* In polling mode there is nobody to wake up (PDMThread will cancel the sleep). */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync NOREF(pDrvIns);
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync NOREF(pThread);
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif /* RT_OS_LINUX */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync
3fc6f92e1808a59d5c1c3002484efd3af72a6603vboxsync return VINF_SUCCESS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync}
0deaf9b7b14fd7b44a999419acd224f002a2b13bvboxsync#endif /* RT_OS_LINUX || RT_OS_DARWIN || RT_OS_SOLARIS */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync/**
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * Set the modem lines.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync *
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @returns VBox status code
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * @param pInterface Pointer to the interface structure.
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync * @param RequestToSend Set to true if this control line should be made active.
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync * @param DataTerminalReady Set to true if this control line should be made active.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool RequestToSend, bool DataTerminalReady)
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync int modemStateSet = 0;
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync int modemStateClear = 0;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (RequestToSend)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync modemStateSet |= TIOCM_RTS;
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync else
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync modemStateClear |= TIOCM_RTS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (DataTerminalReady)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync modemStateSet |= TIOCM_DTR;
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync else
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync modemStateClear |= TIOCM_DTR;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (modemStateSet)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIS, &modemStateSet);
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (modemStateClear)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIC, &modemStateClear);
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync#elif defined(RT_OS_WINDOWS)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (RequestToSend)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync EscapeCommFunction(pThis->hDeviceFile, SETRTS);
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync else
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync EscapeCommFunction(pThis->hDeviceFile, CLRRTS);
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (DataTerminalReady)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync EscapeCommFunction(pThis->hDeviceFile, SETDTR);
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync else
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync EscapeCommFunction(pThis->hDeviceFile, CLRDTR);
f2f744fb6b4e8cd5db2d98026156d350d4c5b99fvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync#endif
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync return VINF_SUCCESS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync/**
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * Sets the TD line into break condition.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync *
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @returns VBox status code.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @param fBreak Set to true to let the device send a break false to put into normal operation.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @thread Any thread.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvHostSerialSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync{
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync if (fBreak)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSBRK);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync else
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCCBRK);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync#elif defined(RT_OS_WINDOWS)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync if (fBreak)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync SetCommBreak(pThis->hDeviceFile);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync else
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync ClearCommBreak(pThis->hDeviceFile);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync#endif
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync return VINF_SUCCESS;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync}
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- driver interface -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/**
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Destruct a char driver instance.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync *
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * Most VM resources are freed by the VM. This callback is provided so that
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * any non-VM resources can be freed correctly.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync *
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pDrvIns The driver instance data.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncstatic DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync{
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync /* Empty the send queue */
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync if (pThis->SendSem != NIL_RTSEMEVENT)
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync {
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync RTSemEventDestroy(pThis->SendSem);
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync pThis->SendSem = NIL_RTSEMEVENT;
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
bb56e9b73a923e975bc18bea69639b4c07e32f60vboxsync int rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hWakeupPipeW = NIL_RTPIPE;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hWakeupPipeR = NIL_RTPIPE;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync# if defined(RT_OS_DARWIN)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync if (pThis->hDeviceFileR != NIL_RTFILE)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync if (pThis->hDeviceFileR != pThis->hDeviceFile)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileClose(pThis->hDeviceFileR);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertRC(rc);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hDeviceFileR = NIL_RTFILE;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync# endif
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync if (pThis->hDeviceFile != NIL_RTFILE)
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync {
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync rc = RTFileClose(pThis->hDeviceFile); AssertRC(rc);
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync pThis->hDeviceFile = NIL_RTFILE;
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync#elif defined(RT_OS_WINDOWS)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CloseHandle(pThis->hEventRecv);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CloseHandle(pThis->hEventSend);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CancelIo(pThis->hDeviceFile);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CloseHandle(pThis->hDeviceFile);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync#endif
23aabe13ea8571e8433d4bfa7b3a857197ac077avboxsync
23aabe13ea8571e8433d4bfa7b3a857197ac077avboxsync if (pThis->pszDevicePath)
23aabe13ea8571e8433d4bfa7b3a857197ac077avboxsync {
23aabe13ea8571e8433d4bfa7b3a857197ac077avboxsync MMR3HeapFree(pThis->pszDevicePath);
23aabe13ea8571e8433d4bfa7b3a857197ac077avboxsync pThis->pszDevicePath = NULL;
23aabe13ea8571e8433d4bfa7b3a857197ac077avboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync}
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Construct a char driver instance.
8bed792bc65abd39393889351f22263ce6c289bfvboxsync *
cba6719bd64ec749967bbe931230452664109857vboxsync * @copydoc FNPDMDRVCONSTRUCT
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
eeec2f0aba1a5a7304026483450d55b52d85e3dcvboxsyncstatic DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t /*fFlags*/)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Init basic data members and interfaces.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hDeviceFile = NIL_RTFILE;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hDeviceFileR = NIL_RTFILE;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hWakeupPipeR = NIL_RTPIPE;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hWakeupPipeW = NIL_RTPIPE;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync#elif defined(RT_OS_WINDOWS)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hEventRecv = INVALID_HANDLE_VALUE;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hEventSend = INVALID_HANDLE_VALUE;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hDeviceFile = INVALID_HANDLE_VALUE;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync#endif
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync pThis->SendSem = NIL_RTSEMEVENT;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* IBase. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync /* ICharConnector. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnWrite = drvHostSerialWrite;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnSetParameters = drvHostSerialSetParameters;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnSetModemLines = drvHostSerialSetModemLines;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnSetBreak = drvHostSerialSetBreak;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Query configuration.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Device */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
9d61cc96134bcb140ed445a8a9eb9fda6ffcb1fbvboxsync AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return rc;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Open the device
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertReturn(pThis->hHaltEventSem != NULL, VERR_NO_MEMORY);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->hEventRecv = CreateEvent(NULL, FALSE, FALSE, NULL);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertReturn(pThis->hEventRecv != NULL, VERR_NO_MEMORY);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertReturn(pThis->hEventSend != NULL, VERR_NO_MEMORY);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync HANDLE hFile = CreateFile(pThis->pszDevicePath,
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync GENERIC_READ | GENERIC_WRITE,
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync 0, // must be opened with exclusive access
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync NULL, // no SECURITY_ATTRIBUTES structure
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync OPEN_EXISTING, // must use OPEN_EXISTING
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync FILE_FLAG_OVERLAPPED, // overlapped I/O
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync NULL); // no template file
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (hFile == INVALID_HANDLE_VALUE)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = RTErrConvertFromWin32(GetLastError());
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->hDeviceFile = hFile;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* for overlapped read */
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync if (!SetCommMask(hFile, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING | EV_RLSD))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync LogRel(("HostSerial#%d: SetCommMask failed with error %d.\n", pDrvIns->iInstance, GetLastError()));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VERR_FILE_IO_ERROR;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = VINF_SUCCESS;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync#else /* !RT_OS_WINDOWS */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync# ifdef RT_OS_LINUX
d9bbd32b2ca16437c0ac753cdf2b7bde3a888c4cvboxsync /* This seems to be necessary on some Linux hosts, otherwise we hang here forever. */
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync fOpen |= RTFILE_O_NON_BLOCK;
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync# endif
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen);
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync# ifdef RT_OS_LINUX
d9bbd32b2ca16437c0ac753cdf2b7bde3a888c4cvboxsync /* RTFILE_O_NON_BLOCK not supported? */
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync if (rc == VERR_INVALID_PARAMETER)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen & ~RTFILE_O_NON_BLOCK);
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync# endif
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync if (RT_SUCCESS(rc))
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileOpen(&pThis->hDeviceFileR, pThis->pszDevicePath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
795333b05cd74f8d4dcc72848a16da2973ba4568vboxsync#endif /* !RT_OS_WINDOWS */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
fe813b3594039ba864493438e78ee0e7132bc445vboxsync AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pThis->pszDevicePath, rc));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync switch (rc)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case VERR_ACCESS_DENIED:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync N_("Cannot open host device '%s' for read/write access. Check the permissions "
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "of that device ('/bin/ls -l %s'): Most probably you need to be member "
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "of the device group. Make sure that you logout/login after changing "
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "the group settings of the current user"),
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#else
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync N_("Cannot open host device '%s' for read/write access. Check the permissions "
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "of that device"),
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pszDevicePath, pThis->pszDevicePath);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync N_("Failed to open host device '%s'"),
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pszDevicePath);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Set to non blocking I/O */
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync fcntl(RTFileToNative(pThis->hDeviceFile), F_SETFL, O_NONBLOCK);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync fcntl(RTFileToNative(pThis->hDeviceFileR), F_SETFL, O_NONBLOCK);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync AssertRCReturn(rc, rc);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#elif defined(RT_OS_WINDOWS)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Set the COMMTIMEOUTS to get non blocking I/O */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync COMMTIMEOUTS comTimeout;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comTimeout.ReadIntervalTimeout = MAXDWORD;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comTimeout.ReadTotalTimeoutMultiplier = 0;
243cc1785504c050523fbc933363759b63fc59f0vboxsync comTimeout.ReadTotalTimeoutConstant = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comTimeout.WriteTotalTimeoutMultiplier = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comTimeout.WriteTotalTimeoutConstant = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync SetCommTimeouts(pThis->hDeviceFile, &comTimeout);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Get the ICharPort interface of the above driver/device.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->pDrvCharPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICHARPORT);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!pThis->pDrvCharPort)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Create the receive, send and monitor threads plus the related send semaphore.
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync */
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pRecvThread, pThis, drvHostSerialRecvThread, drvHostSerialWakeupRecvThread, 0, RTTHREADTYPE_IO, "SerRecv");
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = RTSemEventCreate(&pThis->SendSem);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync AssertRC(rc);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pSendThread, pThis, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "SerSend");
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
5dcae142d05d0d6307e097f026b53a048b8ef949vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync /* Linux & darwin needs a separate thread which monitors the status lines. */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# ifndef RT_OS_LINUX
cae3b8810c39392e70dfb12b951431018a80fcbavboxsync ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &pThis->fStatusLines);
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostSerialMonitorThread, drvHostSerialWakeupMonitorThread, 0, RTTHREADTYPE_IO, "SerMon");
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create monitor thread"), pDrvIns->iInstance);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync /*
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync * Register release statistics.
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#ifdef RT_OS_DARWIN /* new Write code, not darwin specific. */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSendOverflows, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes overflowed", "/Devices/HostSerial%d/SendOverflow", pDrvIns->iInstance);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Char driver registration record.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncconst PDMDRVREG g_DrvHostSerial =
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* u32Version */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDM_DRVREG_VERSION,
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync /* szName */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "Host Serial",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* szRCMod */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync "",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* szR0Mod */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync "",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync/* pszDescription */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "Host serial driver.",
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* fFlags */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* fClass. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDM_DRVREG_CLASS_CHAR,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* cMaxInstances */
ad48e47654d22f79b025dc4b21cb162cb123801avboxsync ~0U,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* cbInstance */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync sizeof(DRVHOSTSERIAL),
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnConstruct */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync drvHostSerialConstruct,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnDestruct */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync drvHostSerialDestruct,
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* pfnRelocate */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnIOCtl */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnPowerOn */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnReset */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnSuspend */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnResume */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnAttach */
cba6719bd64ec749967bbe931230452664109857vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnDetach */
8bed792bc65abd39393889351f22263ce6c289bfvboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnPowerOff */
8bed792bc65abd39393889351f22263ce6c289bfvboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnSoftReset */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* u32EndVersion */
cba6719bd64ec749967bbe931230452664109857vboxsync PDM_DRVREG_VERSION
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync};
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync