DrvHostSerial.cpp revision dcba8de9fb9216170ee6740b57a51b3c8f2a55fc
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** $Id$ */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** @file
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * VBox stream I/O devices: Host serial driver
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Contributed by: Alexander Eichner
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Copyright (C) 2006-2007 innotek GmbH
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * General Public License as published by the Free Software Foundation,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * If you received this file as part of a commercial VirtualBox
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * distribution, then only the terms of your commercial VirtualBox
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * license agreement apply instead of the previous paragraph.
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/stream.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <iprt/semaphore.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <iprt/file.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include <iprt/alloc.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#ifdef RT_OS_LINUX
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync# include <errno.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <termios.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <sys/types.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <fcntl.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <string.h>
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync# include <unistd.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <sys/poll.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#elif defined(RT_OS_WINDOWS)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync# include <windows.h>
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#include "Builtins.h"
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** Size of the send fifo queue (in bytes) */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#define CHAR_MAX_SEND_QUEUE 0x80
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#define CHAR_MAX_SEND_QUEUE_MASK 0x7f
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/*******************************************************************************
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync* Structures and Typedefs *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync*******************************************************************************/
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Char driver instance data.
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. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDMICHAR IChar;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** Receive thread. */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PPDMTHREAD pReceiveThread;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** Send thread. */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PPDMTHREAD pSendThread;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Send event semephore */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync RTSEMEVENT SendSem;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** the device path */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync char *pszDevicePath;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_LINUX
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** the device handle */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync RTFILE DeviceFile;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The read end of the control pipe */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync RTFILE WakeupPipeR;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The write end of the control pipe */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync RTFILE WakeupPipeW;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#elif 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 */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE hEventReceive;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /** The event semaphore for overlapped sending */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE hEventSend;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Internal send FIFO queue */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync uint8_t aSendQueue[CHAR_MAX_SEND_QUEUE];
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync uint32_t iSendQueueHead;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync uint32_t iSendQueueTail;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** Read/write statistics */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync STAMCOUNTER StatBytesRead;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync STAMCOUNTER StatBytesWritten;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** Converts a pointer to DRVCHAR::IChar to a PDRVHOSTSERIAL. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#define PDMICHAR_2_DRVHOSTSERIAL(pInterface) ( (PDRVHOSTSERIAL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTSERIAL, IChar)) )
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- IBase -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Queries an interface to the driver.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @returns Pointer to interface.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @returns NULL if the interface was not supported by the driver.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param pInterface Pointer to this interface structure.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param enmInterface The requested interface identification.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncstatic DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync switch (enmInterface)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case PDMINTERFACE_BASE:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return &pDrvIns->IBase;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case PDMINTERFACE_CHAR:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return &pData->IChar;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return NULL;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- IChar -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/** @copydoc PDMICHAR::pfnWrite */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncstatic DECLCALLBACK(int) drvHostSerialWrite(PPDMICHAR pInterface, const void *pvBuf, size_t cbWrite)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDRVHOSTSERIAL pData = 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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync for (uint32_t i=0;i<cbWrite;i++)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync uint32_t idx = pData->iSendQueueHead;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->aSendQueue[idx] = pbBuffer[i];
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync idx = (idx + 1) & CHAR_MAX_SEND_QUEUE_MASK;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync STAM_COUNTER_INC(&pData->StatBytesWritten);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync ASMAtomicXchgU32(&pData->iSendQueueHead, idx);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync RTSemEventSignal(pData->SendSem);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncstatic DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHAR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDRVHOSTSERIAL pData = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#ifdef RT_OS_LINUX
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#ifdef RT_OS_LINUX
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:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync baud_rate = B9600;
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 */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync termiosSetup->c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync tcsetattr(pData->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
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync SetCommState(pData->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{
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE haWait[2];
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync haWait[0] = pData->hEventSend;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync haWait[1] = pData->hHaltEventSem;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync int rc = RTSemEventWait(pData->SendSem, RT_INDEFINITE_WAIT);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (VBOX_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Write the character to the host device.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync while ( pThread->enmState == PDMTHREADSTATE_RUNNING
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync && pData->iSendQueueTail != pData->iSendQueueHead)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync unsigned cbProcessed = 1;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#if defined(RT_OS_LINUX)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync rc = RTFileWrite(pData->DeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed, NULL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#elif defined(RT_OS_WINDOWS)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD cbBytesWritten;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync OVERLAPPED overlapped;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync memset(&overlapped, 0, sizeof(overlapped));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync overlapped.hEvent = pData->hEventSend;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (!WriteFile(pData->hDeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed, &cbBytesWritten, &overlapped))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD dwRet = GetLastError();
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet == ERROR_IO_PENDING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /*
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync * write blocked, wait ...
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet != WAIT_OBJECT_0)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = RTErrConvertFromWin32(dwRet);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (VBOX_SUCCESS(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync Assert(cbProcessed);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->iSendQueueTail++;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->iSendQueueTail &= CHAR_MAX_SEND_QUEUE_MASK;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync else if (VBOX_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync LogRel(("HostSerial#%d: Serial Write failed with %Vrc; terminating send thread\n", pDrvIns->iInstance, rc));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
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{
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int rc;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = RTSemEventSignal(pData->SendSem);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (RT_FAILURE(rc))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return rc;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (!SetEvent(pData->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 */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsyncstatic DECLCALLBACK(int) drvHostSerialReceiveThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(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;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE haWait[2];
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync haWait[0] = pData->hEventReceive;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync haWait[1] = pData->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
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#if defined(RT_OS_LINUX)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync size_t cbRead;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync struct pollfd aFDs[2];
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].fd = pData->DeviceFile;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].events = POLLIN;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[0].revents = 0;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[1].fd = pData->WakeupPipeR;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[1].events = POLLIN | POLLERR | POLLHUP;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync aFDs[1].revents = 0;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = poll(aFDs, ELEMENTS(aFDs), -1);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (rc < 0)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* poll failed for whatever reason */
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 */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync char ch;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync size_t cbRead;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync RTFileRead(pData->WakeupPipeR, &ch, 1, &cbRead);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync continue;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = RTFileRead(pData->DeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (VBOX_FAILURE(rc))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync LogRel(("HostSerial#%d: Read failed with %Vrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync cbRemaining = cbRead;
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#elif defined(RT_OS_WINDOWS)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD dwEventMask = 0;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD dwNumberOfBytesTransferred;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync OVERLAPPED overlapped;
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync memset(&overlapped, 0, sizeof(overlapped));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync overlapped.hEvent = pData->hEventReceive;
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (!WaitCommEvent(pData->hDeviceFile, &dwEventMask, &overlapped))
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync DWORD dwRet = GetLastError();
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet == ERROR_IO_PENDING)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (dwRet != WAIT_OBJECT_0)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* notification to terminate */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync LogRel(("HostSerial#%d: Wait failed with error %Vrc; terminating the worker thread.\n", pDrvIns->iInstance, RTErrConvertFromWin32(dwRet)));
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync break;
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync }
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* this might have changed in the meantime */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pThread->enmState != PDMTHREADSTATE_RUNNING)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync break;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (!ReadFile(pData->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &overlapped))
243cc1785504c050523fbc933363759b63fc59f0vboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync LogRel(("HostSerial#%d: Read failed with error %Vrc; terminating the worker thread.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError())));
243cc1785504c050523fbc933363759b63fc59f0vboxsync break;
243cc1785504c050523fbc933363759b63fc59f0vboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync cbRemaining = dwNumberOfBytesTransferred;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
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;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync rc = pData->pDrvCharPort->pfnNotifyRead(pData->pDrvCharPort, pbBuffer, &cbProcessed);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (VBOX_SUCCESS(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pbBuffer += cbProcessed;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync cbRemaining -= cbProcessed;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync STAM_COUNTER_ADD(&pData->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 {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync LogRel(("HostSerial#%d: NotifyRead failed with %Vrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync break;
3b9591b897f4b581f0be311535f93fd3a555c576vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
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) drvHostSerialWakeupReceiveThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync{
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_LINUX
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return RTFileWrite(pData->WakeupPipeW, "", 1, NULL);
d3de369f8d66bc3c40cd338831bd5908c2f82d16vboxsync#elif defined(RT_OS_WINDOWS)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (!SetEvent(pData->hHaltEventSem))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return RTErrConvertFromWin32(GetLastError());
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return VINF_SUCCESS;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#else
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync# error adapt me!
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync}
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/* -=-=-=-=- driver interface -=-=-=-=- */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Construct a char driver instance.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @returns VBox status.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param pDrvIns The driver instance data.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * If the registration structure is needed,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * pDrvIns->pDrvReg points to it.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param pCfgHandle Configuration node handle for the driver. Use this to
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * obtain the configuration of the driver instance. It's
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * also found in pDrvIns->pCfgHandle as it's expected to
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * be used frequently in this function.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncstatic DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Init basic data members and interfaces.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
b8939a8db837f27574e06c82474888bdd058ce17vboxsync#ifdef RT_OS_LINUX
b8939a8db837f27574e06c82474888bdd058ce17vboxsync pData->DeviceFile = NIL_RTFILE;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync pData->WakeupPipeR = NIL_RTFILE;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync pData->WakeupPipeW = NIL_RTFILE;
b8939a8db837f27574e06c82474888bdd058ce17vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* IBase. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* IChar. */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->IChar.pfnWrite = drvHostSerialWrite;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->IChar.pfnSetParameters = drvHostSerialSetParameters;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Query configuration.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Device */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync int rc = CFGMR3QueryStringAlloc(pCfgHandle, "DevicePath", &pData->pszDevicePath);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (VBOX_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Vra.\n", rc));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return rc;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Open the device
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#ifdef RT_OS_WINDOWS
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertReturn(pData->hHaltEventSem != NULL, VERR_NO_MEMORY);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->hEventReceive = CreateEvent(NULL, FALSE, FALSE, NULL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertReturn(pData->hEventReceive != NULL, VERR_NO_MEMORY);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertReturn(pData->hEventSend != NULL, VERR_NO_MEMORY);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync HANDLE hFile = CreateFile(pData->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 {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->hDeviceFile = hFile;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync /* for overlapped read */
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (!SetCommMask(hFile, EV_RXCHAR))
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (VBOX_FAILURE(rc))
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pData->pszDevicePath, rc));
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync switch (rc)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync case VERR_ACCESS_DENIED:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#ifdef RT_OS_LINUX
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
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->pszDevicePath, pData->pszDevicePath);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync default:
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync N_("Failed to open host device '%s'"),
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->pszDevicePath);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Set to non blocking I/O */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#ifdef RT_OS_LINUX
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync fcntl(pData->DeviceFile, F_SETFL, O_NONBLOCK);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int aFDs[2];
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pipe(aFDs) != 0)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int rc = RTErrConvertFromErrno(errno);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertRC(rc);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync return rc;
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->WakeupPipeR = aFDs[0];
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->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
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync SetCommTimeouts(pData->hDeviceFile, &comTimeout);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /*
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Get the ICharPort interface of the above driver/device.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->pDrvCharPort = (PPDMICHARPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_CHAR_PORT);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (!pData->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
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pData->pReceiveThread, pData, drvHostSerialReceiveThread, drvHostSerialWakeupReceiveThread, 0, RTTHREADTYPE_IO, "Char Receive");
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (VBOX_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync rc = RTSemEventCreate(&pData->SendSem);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync AssertRC(rc);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pData->pSendThread, pData, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "Serial Send");
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync if (VBOX_FAILURE(rc))
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync return VINF_SUCCESS;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Destruct a char driver instance.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Most VM resources are freed by the VM. This callback is provided so that
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * any non-VM resources can be freed correctly.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync *
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * @param pDrvIns The driver instance data.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncstatic DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* Empty the send queue */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->iSendQueueTail = pData->iSendQueueHead = 0;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync RTSemEventDestroy(pData->SendSem);
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync pData->SendSem = NIL_RTSEMEVENT;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#if defined(RT_OS_LINUX)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pData->WakeupPipeW != NIL_RTFILE)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int rc = RTFileClose(pData->WakeupPipeW);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertRC(rc);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->WakeupPipeW = NIL_RTFILE;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pData->WakeupPipeR != NIL_RTFILE)
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int rc = RTFileClose(pData->WakeupPipeR);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertRC(rc);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->WakeupPipeR = NIL_RTFILE;
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync }
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync if (pData->DeviceFile != NIL_RTFILE)
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync {
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync int rc = RTFileClose(pData->DeviceFile);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync AssertRC(rc);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync pData->DeviceFile = NIL_RTFILE;
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync }
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#elif defined(RT_OS_WINDOWS)
b333b3925e4d1e083ae089988cb3b5efb126d81fvboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync CloseHandle(pData->hEventReceive);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync CloseHandle(pData->hEventSend);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync CancelIo(pData->hDeviceFile);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync CloseHandle(pData->hDeviceFile);
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync
e554e8c589d84d4df49504e096f81dfa48c2a06evboxsync#endif
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync}
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync/**
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync * Char driver registration record.
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsyncconst PDMDRVREG g_DrvHostSerial =
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync{
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* u32Version */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync PDM_DRVREG_VERSION,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* szDriverName */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync "Host Serial",
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* 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,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnIOCtl */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnPowerOn */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnReset */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnSuspend */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnResume */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /* pfnDetach */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL,
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync /** pfnPowerOff */
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync NULL
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync};
a2e6357e0295f680b36aaf31bedd6409a5336165vboxsync