DrvHostSerial.cpp revision 36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1
7df95d48add893eab9003d793e18c099e126edf9vboxsync/* $Id$ */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** @file
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * VBox stream I/O devices: Host serial driver
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync * Copyright (C) 2006-2010 Sun Microsystems, Inc.
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.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * additional information or have any questions.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*******************************************************************************
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync* Header Files *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync*******************************************************************************/
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <VBox/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>
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
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * structs. Thatswhy 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
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync#include "../Builtins.h"
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** Size of the send fifo queue (in bytes) */
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync#ifdef RT_OS_DARWIN
a9e040e11af94d3457b824f2942d11375f16f598vboxsync /** @todo This is really desperate, but it seriously looks like
a9e040e11af94d3457b824f2942d11375f16f598vboxsync * the data is arriving way too fast for us to push over. 9600
a9e040e11af94d3457b824f2942d11375f16f598vboxsync * baud and zoc reports sending at 12000+ chars/sec... */
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# define CHAR_MAX_SEND_QUEUE 0x400
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# define CHAR_MAX_SEND_QUEUE_MASK 0x3ff
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync#else
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# define CHAR_MAX_SEND_QUEUE 0x80
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# define CHAR_MAX_SEND_QUEUE_MASK 0x7f
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync#endif
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;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Send event semephore */
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 */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync RTFILE DeviceFile;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
a9e040e11af94d3457b824f2942d11375f16f598vboxsync /** The device handle used for reading.
a9e040e11af94d3457b824f2942d11375f16f598vboxsync * Used to prevent the read selecto from blocking the writes. */
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync RTFILE DeviceFileR;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The read end of the control pipe */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync RTFILE WakeupPipeR;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The write end of the control pipe */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync RTFILE WakeupPipeW;
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 */
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint8_t volatile aSendQueue[CHAR_MAX_SEND_QUEUE];
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint32_t volatile iSendQueueHead;
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint32_t volatile iSendQueueTail;
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 {
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync#ifdef RT_OS_DARWIN /* don't wanna break the others here. */
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint32_t iHead = ASMAtomicUoReadU32(&pThis->iSendQueueHead);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint32_t iTail = ASMAtomicUoReadU32(&pThis->iSendQueueTail);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync int32_t cbAvail = iTail > iHead
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync ? iTail - iHead - 1
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync : CHAR_MAX_SEND_QUEUE - (iHead - iTail) - 1;
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync if (cbAvail <= 0)
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync {
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# ifdef DEBUG
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync uint64_t volatile u64Now = RTTimeNanoTS(); NOREF(u64Now);
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# endif
cb130fe54ffed3568729e3546b9aa73190e1c1advboxsync Log(("%s: dropping %d chars (cbAvail=%d iHead=%d iTail=%d)\n", __FUNCTION__, cbWrite - i , cbAvail, iHead, iTail));
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync STAM_COUNTER_INC(&pThis->StatSendOverflows);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync break;
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync }
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync pThis->aSendQueue[iHead] = pbBuffer[i];
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync STAM_COUNTER_INC(&pThis->StatBytesWritten);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync ASMAtomicWriteU32(&pThis->iSendQueueHead, (iHead + 1) & CHAR_MAX_SEND_QUEUE_MASK);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync if (cbAvail < CHAR_MAX_SEND_QUEUE / 4)
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync {
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync RTSemEventSignal(pThis->SendSem);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync RTThreadYield();
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#else /* old code */
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint32_t idx = ASMAtomicUoReadU32(&pThis->iSendQueueHead);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->aSendQueue[idx] = pbBuffer[i];
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync idx = (idx + 1) & CHAR_MAX_SEND_QUEUE_MASK;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync STAM_COUNTER_INC(&pThis->StatBytesWritten);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync ASMAtomicWriteU32(&pThis->iSendQueueHead, idx);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#endif /* old code */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync RTSemEventSignal(pThis->SendSem);
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (Bps) {
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;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync if (ioctl(pThis->DeviceFile, 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;
36ea08d3a9cad2208ca17245ac69fc0e57b0a7d1vboxsync ioctl(pThis->DeviceFile, 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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (chParity) {
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (cDataBits) {
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (cStopBits) {
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
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync tcsetattr(pThis->DeviceFile, TCSANOW, termiosSetup);
dcba8de9fb9216170ee6740b57a51b3c8f2a55fcvboxsync RTMemTmpFree(termiosSetup);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#elif defined(RT_OS_WINDOWS)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync comSetup->DCBlength = sizeof(DCB);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (Bps) {
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (chParity) {
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (cStopBits) {
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#ifdef RT_OS_DARWIN
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* copy the send queue so we get a linear buffer with the maximal size. */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync uint8_t abBuf[sizeof(pThis->aSendQueue)];
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync uint32_t cb = 0;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync uint32_t iTail = ASMAtomicUoReadU32(&pThis->iSendQueueTail);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync uint32_t iHead = ASMAtomicUoReadU32(&pThis->iSendQueueHead);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (iTail == iHead)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync do
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync abBuf[cb++] = pThis->aSendQueue[iTail];
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync iTail = (iTail + 1) & CHAR_MAX_SEND_QUEUE_MASK;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync } while (iTail != iHead);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync ASMAtomicWriteU32(&pThis->iSendQueueTail, iTail);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* write it. */
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# ifdef DEBUG
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync uint64_t volatile u64Now = RTTimeNanoTS(); NOREF(u64Now);
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# endif
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync size_t cbWritten;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = RTFileWrite(pThis->DeviceFile, abBuf, cb, &cbWritten);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (rc == VERR_TRY_AGAIN)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync cbWritten = 0;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (cbWritten < cb && (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 uint8_t const *pbSrc = &abBuf[0];
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* advance */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync cb -= cbWritten;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync pbSrc += cbWritten;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* wait */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync fd_set WrSet;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync FD_ZERO(&WrSet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync FD_SET(pThis->DeviceFile, &WrSet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync fd_set XcptSet;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync FD_ZERO(&XcptSet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync FD_SET(pThis->DeviceFile, &XcptSet);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync rc = select(pThis->DeviceFile + 1, NULL, &WrSet, &XcptSet, NULL);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /** @todo check rc? */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync /* try write more */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = RTFileWrite(pThis->DeviceFile, pbSrc, cb, &cbWritten);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (rc == VERR_TRY_AGAIN)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync cbWritten = 0;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync else if (RT_FAILURE(rc))
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync else if (cbWritten >= cb)
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = VINF_SUCCESS;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync } /* wait/write loop */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# 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;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync if (!WriteFile(pThis->hDeviceFile, abBuf, cb, &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 {
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event sempahore is set but the thread is still in running state\n"));
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync break;
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync else
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync rc = RTErrConvertFromWin32(dwRet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# 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 }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync } /* write loop */
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#else /* old code */
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint32_t iTail;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync while ( pThread->enmState == PDMTHREADSTATE_RUNNING
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync && (iTail = ASMAtomicUoReadU32(&pThis->iSendQueueTail)) != ASMAtomicUoReadU32(&pThis->iSendQueueHead))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync /** @todo process more than one byte? */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync unsigned cbProcessed = 1;
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync uint8_t abBuf[1];
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync abBuf[0] = pThis->aSendQueue[iTail];
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync rc = RTFileWrite(pThis->DeviceFile, abBuf, cbProcessed, NULL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# elif defined(RT_OS_WINDOWS)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD cbBytesWritten;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync memset(&pThis->overlappedSend, 0, sizeof(pThis->overlappedSend));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->overlappedSend.hEvent = pThis->hEventSend;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync if (!WriteFile(pThis->hDeviceFile, abBuf, cbProcessed, &cbBytesWritten, &pThis->overlappedSend))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync dwRet = GetLastError();
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet == ERROR_IO_PENDING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /*
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * write blocked, wait ...
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync */
b5523a351ce3a0829df2421672ef4bf1481970bcvboxsync dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet != WAIT_OBJECT_0)
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync {
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event sempahore is set but the thread is still in running state\n"));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = RTErrConvertFromWin32(dwRet);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync# endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_SUCCESS(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync Assert(cbProcessed == 1);
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync ASMAtomicWriteU32(&pThis->iSendQueueTail, (iTail + 1) & CHAR_MAX_SEND_QUEUE_MASK);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync else if (RT_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
fe813b3594039ba864493438e78ee0e7132bc445vboxsync LogRel(("HostSerial#%d: Serial Write failed with %Rrc; terminating send thread\n", pDrvIns->iInstance, rc));
4e12eda9a6e918332bb14827546097d878ef8a2dvboxsync return rc;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync#endif /* old code */
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 */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsyncstatic 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);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync FD_SET(pThis->DeviceFileR, &RdSet);
7df95d48add893eab9003d793e18c099e126edf9vboxsync FD_SET(pThis->WakeupPipeR, &RdSet);
7df95d48add893eab9003d793e18c099e126edf9vboxsync fd_set XcptSet;
7df95d48add893eab9003d793e18c099e126edf9vboxsync FD_ZERO(&XcptSet);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync FD_SET(pThis->DeviceFileR, &XcptSet);
7df95d48add893eab9003d793e18c099e126edf9vboxsync FD_SET(pThis->WakeupPipeR, &XcptSet);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync# if 1 /* it seems like this select is blocking the write... */
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync rc = select(RT_MAX(pThis->WakeupPipeR, pThis->DeviceFileR) + 1, &RdSet, NULL, &XcptSet, NULL);
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync# else
1f72a47e266d9b7498b6a06aacf53a23ff874bc2vboxsync struct timeval tv = { 0, 1000 };
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync rc = select(RT_MAX(pThis->WakeupPipeR, pThis->DeviceFileR) + 1, &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;
7df95d48add893eab9003d793e18c099e126edf9vboxsync if ( FD_ISSET(pThis->WakeupPipeR, &RdSet)
7df95d48add893eab9003d793e18c099e126edf9vboxsync || FD_ISSET(pThis->WakeupPipeR, &XcptSet))
ccc1001951ecd639b15b3034260c6012423349b3vboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync rc = RTFileRead(pThis->WakeupPipeR, abBuffer, 1, &cbRead);
ccc1001951ecd639b15b3034260c6012423349b3vboxsync if (RT_FAILURE(rc))
ccc1001951ecd639b15b3034260c6012423349b3vboxsync {
ccc1001951ecd639b15b3034260c6012423349b3vboxsync LogRel(("HostSerial#%d: draining the wakekup 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. */
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync rc = RTFileRead(pThis->DeviceFileR, 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];
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync aFDs[0].fd = pThis->DeviceFile;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].events = POLLIN;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].revents = 0;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync aFDs[1].fd = pThis->WakeupPipeR;
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;
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 */
ccc1001951ecd639b15b3034260c6012423349b3vboxsync RTFileRead(pThis->WakeupPipeR, &abBuffer, 1, &cbRead);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync continue;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = RTFileRead(pThis->DeviceFile, 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 */
fdc1cae8a7a45e9299077dd0270c3736b02e4e97vboxsync AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event sempahore 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 */
9f9f83ee5948916d644046a79836873db40bfc88vboxsyncstatic 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)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return RTFileWrite(pThis->WakeupPipeW, "", 1, NULL);
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;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync unsigned uStatusLinesToCheck = 0;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_LE | TIOCM_CTS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync return VINF_SUCCESS;
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync {
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync uint32_t newStatusLine = 0;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync unsigned int statusLines;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# ifdef RT_OS_LINUX
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync /*
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * Wait for status line change.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
86ab8383a94d88eb3e2a6f571b813762ef15b394vboxsync rc = ioctl(pThis->DeviceFile, TIOCMIWAIT, uStatusLinesToCheck);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (pThread->enmState != PDMTHREADSTATE_RUNNING)
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync break;
250b90102707676de579dd958c136dcab247b8a0vboxsync if (rc < 0)
250b90102707676de579dd958c136dcab247b8a0vboxsync {
250b90102707676de579dd958c136dcab247b8a0vboxsyncioctl_error:
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
fe813b3594039ba864493438e78ee0e7132bc445vboxsync N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pszDevicePath, RTErrConvertFromErrno(errno));
250b90102707676de579dd958c136dcab247b8a0vboxsync break;
250b90102707676de579dd958c136dcab247b8a0vboxsync }
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = ioctl(pThis->DeviceFile, TIOCMGET, &statusLines);
250b90102707676de579dd958c136dcab247b8a0vboxsync if (rc < 0)
250b90102707676de579dd958c136dcab247b8a0vboxsync goto ioctl_error;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# else /* !RT_OS_LINUX */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync /*
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync * Poll for the status line change.
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync rc = ioctl(pThis->DeviceFile, 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 }
2a19a4b8f5e3264dfc90324291e8afc6b906a15cvboxsync if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync {
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync continue;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync }
8d9dea2b1f501bfd1710836ecc5b5223c117d900vboxsync pThis->fStatusLines = statusLines;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif /* !RT_OS_LINUX */
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_CAR)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_DCD;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_RNG)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_RI;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_LE)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (statusLines & TIOCM_CTS)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync }
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;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# if 0
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync unsigned int uSerialLineFlags;
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync unsigned int uSerialLineStatus;
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync unsigned int uIoctl;
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
b8eec6346e7fdb58d20a6943f968494715412c81vboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync /*
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * Linux is a bit difficult as the thread is sleeping in an ioctl call.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * So there is no way to have a wakeup pipe.
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync *
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * 1. Thatswhy we set the serial device into loopback mode and change one of the
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * modem control bits.
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * This should make the ioctl call return.
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync *
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * 2. We still got reports about long shutdown times. It may bepossible
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * that the loopback mode is not implemented on all devices.
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * The next possible solution is to close the device file to make the ioctl
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * return with EBADF and be able to suspend the thread.
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync *
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * 3. The second approach doesn't work too, the ioctl doesn't return.
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync * But it seems that the ioctl is interruptible (return code in errno is EINTR).
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# if 0 /* Disabled because it does not work for all. */
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync /* Get current status of control lines. */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = ioctl(pThis->DeviceFile, TIOCMGET, &uSerialLineStatus);
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync if (rc < 0)
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync goto ioctl_error;
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync uSerialLineFlags = TIOCM_LOOP;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = ioctl(pThis->DeviceFile, TIOCMBIS, &uSerialLineFlags);
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync if (rc < 0)
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync goto ioctl_error;
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync /*
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync * Change current level on the RTS pin to make the ioctl call return in the
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync * monitor thread.
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync */
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync uIoctl = (uSerialLineStatus & TIOCM_CTS) ? TIOCMBIC : TIOCMBIS;
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync uSerialLineFlags = TIOCM_RTS;
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = ioctl(pThis->DeviceFile, uIoctl, &uSerialLineFlags);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (rc < 0)
3fc6f92e1808a59d5c1c3002484efd3af72a6603vboxsync goto ioctl_error;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync /* Change RTS back to the previous level. */
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync uIoctl = (uIoctl == TIOCMBIC) ? TIOCMBIS : TIOCMBIC;
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = ioctl(pThis->DeviceFile, uIoctl, &uSerialLineFlags);
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync if (rc < 0)
3fc6f92e1808a59d5c1c3002484efd3af72a6603vboxsync goto ioctl_error;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync /*
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync * Set serial device into normal state.
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync */
9eac7269dd9a45b093ee8bbec23c69263aa9e0bdvboxsync uSerialLineFlags = TIOCM_LOOP;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = ioctl(pThis->DeviceFile, TIOCMBIC, &uSerialLineFlags);
db3cb946a1e459bf2a3f3292f481093eb526ebc0vboxsync if (rc >= 0)
db3cb946a1e459bf2a3f3292f481093eb526ebc0vboxsync return VINF_SUCCESS;
4a61dadcdd5fbace94426335d7a985ff31936a2cvboxsync
3fc6f92e1808a59d5c1c3002484efd3af72a6603vboxsyncioctl_error:
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
fe813b3594039ba864493438e78ee0e7132bc445vboxsync N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pszDevicePath, RTErrConvertFromErrno(errno));
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# if 0
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync /* Close file to make ioctl return. */
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync RTFileClose(pData->DeviceFile);
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync /* Open again to make use after suspend possible again. */
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
0ff7152ccdcc57edca12c5f17b9699c66eeff975vboxsync AssertMsgRC(rc, ("Opening device file again failed rc=%Rrc\n", rc));
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync if (RT_FAILURE(rc))
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync PDMDrvHlpVMSetRuntimeError(pDrvIns, false, "DrvHostSerialFail",
0ff7152ccdcc57edca12c5f17b9699c66eeff975vboxsync N_("Opening failed for serial host device '%s' (%Rrc). The device will not work"),
fb34b57e69a76bea498e3a3b9adebe1d526d7f78vboxsync pData->pszDevicePath, rc);
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
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)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ioctl(pThis->DeviceFile, TIOCMBIS, &modemStateSet);
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync if (modemStateClear)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ioctl(pThis->DeviceFile, TIOCMBIC, &modemStateClear);
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);
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)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync ioctl(pThis->DeviceFile, TIOCSBRK);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync else
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync ioctl(pThis->DeviceFile, 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 */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->iSendQueueTail = pThis->iSendQueueHead = 0;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync RTSemEventDestroy(pThis->SendSem);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->SendSem = NIL_RTSEMEVENT;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pThis->WakeupPipeW != NIL_RTFILE)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int rc = RTFileClose(pThis->WakeupPipeW);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertRC(rc);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->WakeupPipeW = NIL_RTFILE;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pThis->WakeupPipeR != NIL_RTFILE)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int rc = RTFileClose(pThis->WakeupPipeR);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertRC(rc);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->WakeupPipeR = NIL_RTFILE;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync# if defined(RT_OS_DARWIN)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pThis->DeviceFileR != NIL_RTFILE)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pThis->DeviceFileR != pThis->DeviceFile)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int rc = RTFileClose(pThis->DeviceFileR);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertRC(rc);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->DeviceFileR = NIL_RTFILE;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync# endif
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pThis->DeviceFile != NIL_RTFILE)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int rc = RTFileClose(pThis->DeviceFile);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertRC(rc);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->DeviceFile = NIL_RTFILE;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync#elif defined(RT_OS_WINDOWS)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CloseHandle(pThis->hEventRecv);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CloseHandle(pThis->hEventSend);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CancelIo(pThis->hDeviceFile);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync CloseHandle(pThis->hDeviceFile);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync#endif
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync}
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Construct a char driver instance.
8bed792bc65abd39393889351f22263ce6c289bfvboxsync *
cba6719bd64ec749967bbe931230452664109857vboxsync * @copydoc FNPDMDRVCONSTRUCT
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsyncstatic 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)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->DeviceFile = NIL_RTFILE;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync pThis->DeviceFileR = NIL_RTFILE;
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->WakeupPipeR = NIL_RTFILE;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->WakeupPipeW = NIL_RTFILE;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync#endif
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
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync/** @todo Initialize all members with NIL values!! The destructor is ALWAYS called. */
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync
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
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
8bed792bc65abd39393889351f22263ce6c289bfvboxsync rc = RTFileOpen(&pThis->DeviceFile, pThis->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync if (RT_SUCCESS(rc))
8bed792bc65abd39393889351f22263ce6c289bfvboxsync rc = RTFileOpen(&pThis->DeviceFileR, pThis->pszDevicePath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
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
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync fcntl(pThis->DeviceFile, F_SETFL, O_NONBLOCK);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# ifdef RT_OS_DARWIN
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync fcntl(pThis->DeviceFileR, F_SETFL, O_NONBLOCK);
d3144b8e0e6d348fc2d93462fcb0a3df2d373d36vboxsync# endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int aFDs[2];
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pipe(aFDs) != 0)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync {
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync rc = RTErrConvertFromErrno(errno);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertRC(rc);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return rc;
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->WakeupPipeR = aFDs[0];
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->WakeupPipeW = aFDs[1];
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 /*
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync * Create the receive, send and monitor threads pluss the related send semaphore.
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMDrvHlpPDMThreadCreate(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
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMDrvHlpPDMThreadCreate(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
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync ioctl(pThis->DeviceFile, TIOCMGET, &pThis->fStatusLines);
6a713fdf2e42488a1179d8c5a9d9cc62e484b1f0vboxsync# endif
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMDrvHlpPDMThreadCreate(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 */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync ~0,
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