ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/* $Id$ */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** @file
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync * Driver that adapts PDMISTREAM into PDMICHARCONNECTOR / PDMICHARPORT.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync *
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * Converts synchronous calls (PDMICHARCONNECTOR::pfnWrite, PDMISTREAM::pfnRead)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * into asynchronous ones.
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync *
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * Note that we don't use a send buffer here to be able to handle
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * dropping of bytes for xmit at device level.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2012 Oracle Corporation
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * available from http://www.virtualbox.org. This file is free software;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * 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.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/*******************************************************************************
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync* Header Files *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync*******************************************************************************/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define LOG_GROUP LOG_GROUP_DRV_CHAR
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmdrv.h>
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#include <iprt/asm.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <iprt/assert.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <iprt/stream.h>
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#include <iprt/semaphore.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/uuid.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include "VBoxDD.h"
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/*******************************************************************************
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync* Defined Constants And Macros *
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync*******************************************************************************/
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/** Converts a pointer to DRVCHAR::ICharConnector to a PDRVCHAR. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync#define PDMICHAR_2_DRVCHAR(pInterface) RT_FROM_MEMBER(pInterface, DRVCHAR, ICharConnector)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/*******************************************************************************
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync* Structures and Typedefs *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync*******************************************************************************/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Char driver instance data.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync *
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @implements PDMICHARCONNECTOR
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsynctypedef struct DRVCHAR
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the driver instance structure. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMDRVINS pDrvIns;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the char port interface of the driver/device above us. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMICHARPORT pDrvCharPort;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the stream interface of the driver below us. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMISTREAM pDrvStream;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Our char interface. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync PDMICHARCONNECTOR ICharConnector;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag to notify the receive thread it should terminate. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync volatile bool fShutdown;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Receive thread ID. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync RTTHREAD ReceiveThread;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Send thread ID. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync RTTHREAD SendThread;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** Send event semaphore */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync RTSEMEVENT SendSem;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Internal send FIFO queue */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync uint8_t volatile u8SendByte;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync bool volatile fSending;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync uint8_t Alignment[2];
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync /** Read/write statistics */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync STAMCOUNTER StatBytesRead;
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync STAMCOUNTER StatBytesWritten;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync} DRVCHAR, *PDRVCHAR;
fa033b734cf3b131680f290326ccbbd23c42946bvboxsyncAssertCompileMemberAlignment(DRVCHAR, StatBytesRead, 8);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/* -=-=-=-=- IBase -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) drvCharQueryInterface(PPDMIBASE pInterface, const char *pszIID)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARCONNECTOR, &pThis->ICharConnector);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return NULL;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/* -=-=-=-=- ICharConnector -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/** @copydoc PDMICHARCONNECTOR::pfnWrite */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvCharWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVCHAR pThis = PDMICHAR_2_DRVCHAR(pInterface);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync const char *pbBuffer = (const char *)pvBuf;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync for (uint32_t i = 0; i < cbWrite; i++)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync if (ASMAtomicXchgBool(&pThis->fSending, true))
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync return VERR_BUFFER_OVERFLOW;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync pThis->u8SendByte = pbBuffer[i];
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync RTSemEventSignal(pThis->SendSem);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync STAM_COUNTER_INC(&pThis->StatBytesWritten);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync }
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return VINF_SUCCESS;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync}
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/** @copydoc PDMICHARCONNECTOR::pfnSetParameters */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvCharSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync /*PDRVCHAR pThis = PDMICHAR_2_DRVCHAR(pInterface); - unused*/
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync return VINF_SUCCESS;
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync}
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync/* -=-=-=-=- receive thread -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync/**
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * Send thread loop - pushes data down thru the driver chain.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync *
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @returns 0 on success.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @param ThreadSelf Thread handle to this thread.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @param pvUser User argument.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncstatic DECLCALLBACK(int) drvCharSendLoop(RTTHREAD ThreadSelf, void *pvUser)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVCHAR pThis = (PDRVCHAR)pvUser;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync int rc = VINF_SUCCESS;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync while (!pThis->fShutdown)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync RTMSINTERVAL cMillies = (rc == VERR_TIMEOUT) ? 50 : RT_INDEFINITE_WAIT;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync rc = RTSemEventWait(pThis->SendSem, cMillies);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync if ( RT_FAILURE(rc)
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync && rc != VERR_TIMEOUT)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync break;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /*
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Write the character to the attached stream (if present).
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if ( pThis->fShutdown
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync || !pThis->pDrvStream)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync break;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync size_t cbProcessed = 1;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync uint8_t ch = pThis->u8SendByte;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &ch, &cbProcessed);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync if (RT_SUCCESS(rc))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync ASMAtomicXchgBool(&pThis->fSending, false);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync Assert(cbProcessed == 1);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync else if (rc == VERR_TIMEOUT)
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync /* Normal case, just means that the stream didn't accept a new
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * character before the timeout elapsed. Just retry. */
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync /* do not change the rc status here, otherwise the (rc == VERR_TIMEOUT) branch
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync * in the wait above will never get executed */
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync /* rc = VINF_SUCCESS; */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync else
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync {
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync LogRel(("Write failed with %Rrc; skipping\n", rc));
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync break;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/* -=-=-=-=- receive thread -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Receive thread loop.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns 0 on success.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param ThreadSelf Thread handle to this thread.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pvUser User argument.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic DECLCALLBACK(int) drvCharReceiveLoop(RTTHREAD ThreadSelf, void *pvUser)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync PDRVCHAR pThis = (PDRVCHAR)pvUser;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync char abBuffer[256];
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync char *pbRemaining = abBuffer;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync size_t cbRemaining = 0;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync int rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync while (!pThis->fShutdown)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (!cbRemaining)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Get block of data from stream driver. */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (pThis->pDrvStream)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pbRemaining = abBuffer;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync cbRemaining = sizeof(abBuffer);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync rc = pThis->pDrvStream->pfnRead(pThis->pDrvStream, abBuffer, &cbRemaining);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync {
fe813b3594039ba864493438e78ee0e7132bc445vboxsync LogFlow(("Read failed with %Rrc\n", rc));
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync break;
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync RTThreadSleep(100);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Send data to guest. */
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync size_t cbProcessed = cbRemaining;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbRemaining, &cbProcessed);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_SUCCESS(rc))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Assert(cbProcessed);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pbRemaining += cbProcessed;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync cbRemaining -= cbProcessed;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else if (rc == VERR_TIMEOUT)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Normal case, just means that the guest didn't accept a new
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * character before the timeout elapsed. Just retry. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync {
fe813b3594039ba864493438e78ee0e7132bc445vboxsync LogFlow(("NotifyRead failed with %Rrc\n", rc));
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync break;
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
362838d79d234a41380be42aae9118850cc3c929vboxsync/**
362838d79d234a41380be42aae9118850cc3c929vboxsync * Set the modem lines.
362838d79d234a41380be42aae9118850cc3c929vboxsync *
362838d79d234a41380be42aae9118850cc3c929vboxsync * @returns VBox status code
362838d79d234a41380be42aae9118850cc3c929vboxsync * @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.
362838d79d234a41380be42aae9118850cc3c929vboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic DECLCALLBACK(int) drvCharSetModemLines(PPDMICHARCONNECTOR pInterface, bool RequestToSend, bool DataTerminalReady)
362838d79d234a41380be42aae9118850cc3c929vboxsync{
362838d79d234a41380be42aae9118850cc3c929vboxsync /* Nothing to do here. */
362838d79d234a41380be42aae9118850cc3c929vboxsync return VINF_SUCCESS;
362838d79d234a41380be42aae9118850cc3c929vboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
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) drvCharSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync{
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync /* Nothing to do here. */
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync return VINF_SUCCESS;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync}
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/* -=-=-=-=- driver interface -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
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) drvCharDestruct(PPDMDRVINS pDrvIns)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync{
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync /*
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * Tell the threads to shut down.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->fShutdown = true;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (pThis->SendSem != NIL_RTSEMEVENT)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync RTSemEventSignal(pThis->SendSem);
1e1273b11e17928ec3c3a8fff45121aa7a169413vboxsync pThis->SendSem = NIL_RTSEMEVENT;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync /*
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * Wait for the threads.
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync * ASSUMES that PDM destroys the driver chain from the bottom and up.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (pThis->ReceiveThread != NIL_RTTHREAD)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync {
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync int rc = RTThreadWait(pThis->ReceiveThread, 30000, NULL);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (RT_SUCCESS(rc))
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->ReceiveThread = NIL_RTTHREAD;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync else
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync LogRel(("Char%d: receive thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (pThis->SendThread != NIL_RTTHREAD)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync int rc = RTThreadWait(pThis->SendThread, 30000, NULL);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (RT_SUCCESS(rc))
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->SendThread = NIL_RTTHREAD;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync else
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync LogRel(("Char%d: send thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync if (pThis->SendSem != NIL_RTSEMEVENT)
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync {
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync RTSemEventDestroy(pThis->SendSem);
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync pThis->SendSem = NIL_RTSEMEVENT;
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync}
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Construct a char driver instance.
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync *
cba6719bd64ec749967bbe931230452664109857vboxsync * @copydoc FNPDMDRVCONSTRUCT
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsyncstatic DECLCALLBACK(int) drvCharConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Init basic data members and interfaces.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->fShutdown = false;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->ReceiveThread = NIL_RTTHREAD;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->SendThread = NIL_RTTHREAD;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->SendSem = NIL_RTSEMEVENT;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* IBase. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pDrvIns->IBase.pfnQueryInterface = drvCharQueryInterface;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync /* ICharConnector. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnWrite = drvCharWrite;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnSetParameters = drvCharSetParameters;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnSetModemLines = drvCharSetModemLines;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->ICharConnector.pfnSetBreak = drvCharSetBreak;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Get the ICharPort interface of the above driver/device.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync pThis->pDrvCharPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICHARPORT);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!pThis->pDrvCharPort)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Char#%d has no char port interface above"), pDrvIns->iInstance);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /*
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Attach driver below and query its stream interface.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMIBASE pBase;
cba6719bd64ec749967bbe931230452664109857vboxsync int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
30adc6dd25ed9fef4d800a6d9f1ab7e765b4c340vboxsync return rc; /* Don't call PDMDrvHlpVMSetError here as we assume that the driver already set an appropriate error */
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pThis->pDrvStream = PDMIBASE_QUERY_INTERFACE(pBase, PDMISTREAM);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!pThis->pDrvStream)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("Char#%d has no stream interface below"), pDrvIns->iInstance);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /*
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * Don't start the receive thread if the driver doesn't support reading
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync */
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync if (pThis->pDrvStream->pfnRead)
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync {
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync rc = RTThreadCreate(&pThis->ReceiveThread, drvCharReceiveLoop, (void *)pThis, 0,
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "CharRecv");
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync if (RT_FAILURE(rc))
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create receive thread"), pDrvIns->iInstance);
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = RTSemEventCreate(&pThis->SendSem);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync AssertRCReturn(rc, rc);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync rc = RTThreadCreate(&pThis->SendThread, drvCharSendLoop, (void *)pThis, 0,
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "CharSend");
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync if (RT_FAILURE(rc))
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create send thread"), pDrvIns->iInstance);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/Char%d/Written", pDrvIns->iInstance);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/Char%d/Read", pDrvIns->iInstance);
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Char driver registration record.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncconst PDMDRVREG g_DrvChar =
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* u32Version */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDM_DRVREG_VERSION,
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync /* szName */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync "Char",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* szRCMod */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync "",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* szR0Mod */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync "",
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pszDescription */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync "Generic char driver.",
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* fFlags */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* fClass. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDM_DRVREG_CLASS_CHAR,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* cMaxInstances */
ad48e47654d22f79b025dc4b21cb162cb123801avboxsync ~0U,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* cbInstance */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync sizeof(DRVCHAR),
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnConstruct */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync drvCharConstruct,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnDestruct */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync drvCharDestruct,
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* pfnRelocate */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NULL,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnIOCtl */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync NULL,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnPowerOn */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync NULL,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnReset */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync NULL,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnSuspend */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync NULL,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnResume */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnAttach */
cba6719bd64ec749967bbe931230452664109857vboxsync NULL,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* pfnDetach */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnPowerOff */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnSoftReset */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* u32EndVersion */
cba6719bd64ec749967bbe931230452664109857vboxsync PDM_DRVREG_VERSION
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync};