summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/VBox/vmm/pdmifs.h118
-rw-r--r--src/VBox/Devices/Makefile.kmk44
-rw-r--r--src/VBox/Devices/Serial/DevSerial.cpp1308
-rw-r--r--src/VBox/Devices/Serial/DevSerialNew.cpp530
-rw-r--r--src/VBox/Devices/Serial/DrvChar.cpp392
-rw-r--r--src/VBox/Devices/Serial/DrvCharNew.cpp451
-rw-r--r--src/VBox/Devices/Serial/DrvHostSerial.cpp1419
-rw-r--r--src/VBox/Devices/Serial/DrvHostSerialNew.cpp713
-rw-r--r--src/VBox/Devices/testcase/Makefile.kmk1
-rw-r--r--src/VBox/Devices/testcase/tstDeviceStructSize.cpp13
-rw-r--r--src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp54
11 files changed, 721 insertions, 4322 deletions
diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h
index f4058fd13c5..d9c24aec069 100644
--- a/include/VBox/vmm/pdmifs.h
+++ b/include/VBox/vmm/pdmifs.h
@@ -1143,124 +1143,6 @@ typedef struct PDMISECKEYHLP
#define PDMISECKEYHLP_IID "7be96168-4156-40ac-86d2-3073bf8b318e"
-/** Pointer to a char port interface. */
-typedef struct PDMICHARPORT *PPDMICHARPORT;
-/**
- * Char port interface (down).
- * Pair with PDMICHARCONNECTOR.
- */
-typedef struct PDMICHARPORT
-{
- /**
- * Deliver data read to the device/driver.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pvBuf Where the read bits are stored.
- * @param pcbRead Number of bytes available for reading/having been read.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnNotifyRead,(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead));
-
- /**
- * Notify the device/driver when the status lines changed.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param fNewStatusLine New state of the status line pins.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnNotifyStatusLinesChanged,(PPDMICHARPORT pInterface, uint32_t fNewStatusLines));
-
- /**
- * Notify the device when the driver buffer is full.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param fFull Buffer full.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnNotifyBufferFull,(PPDMICHARPORT pInterface, bool fFull));
-
- /**
- * Notify the device/driver that a break occurred.
- *
- * @returns VBox statsus code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnNotifyBreak,(PPDMICHARPORT pInterface));
-} PDMICHARPORT;
-/** PDMICHARPORT interface ID. */
-#define PDMICHARPORT_IID "22769834-ea8b-4a6d-ade1-213dcdbd1228"
-
-/** @name Bit mask definitions for status line type.
- * @{ */
-#define PDMICHARPORT_STATUS_LINES_DCD RT_BIT(0)
-#define PDMICHARPORT_STATUS_LINES_RI RT_BIT(1)
-#define PDMICHARPORT_STATUS_LINES_DSR RT_BIT(2)
-#define PDMICHARPORT_STATUS_LINES_CTS RT_BIT(3)
-/** @} */
-
-
-/** Pointer to a char interface. */
-typedef struct PDMICHARCONNECTOR *PPDMICHARCONNECTOR;
-/**
- * Char connector interface (up).
- * Pair with PDMICHARPORT.
- */
-typedef struct PDMICHARCONNECTOR
-{
- /**
- * Write bits.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pvBuf Where to store the write bits.
- * @param cbWrite Number of bytes to write.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite));
-
- /**
- * Set device parameters.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param Bps Speed of the serial connection. (bits per second)
- * @param chParity Parity method: 'E' - even, 'O' - odd, 'N' - none.
- * @param cDataBits Number of data bits.
- * @param cStopBits Number of stop bits.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnSetParameters,(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity,
- unsigned cDataBits, unsigned cStopBits));
-
- /**
- * Set the state of the modem lines.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param fRequestToSend Set to true to make the Request to Send line active otherwise to 0.
- * @param fDataTerminalReady Set to true to make the Data Terminal Ready line active otherwise 0.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnSetModemLines,(PPDMICHARCONNECTOR pInterface, bool fRequestToSend, bool fDataTerminalReady));
-
- /**
- * Sets the TD line into break condition.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param fBreak Set to true to let the device send a break false to put into normal operation.
- * @thread Any thread.
- */
- DECLR3CALLBACKMEMBER(int, pfnSetBreak,(PPDMICHARCONNECTOR pInterface, bool fBreak));
-} PDMICHARCONNECTOR;
-/** PDMICHARCONNECTOR interface ID. */
-#define PDMICHARCONNECTOR_IID "4ad5c190-b408-4cef-926f-fbffce0dc5cc"
-
-
/** Pointer to a stream interface. */
typedef struct PDMISTREAM *PPDMISTREAM;
/**
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index e6a108794fc..d02c5943d7e 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -128,8 +128,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
$(if $(VBOX_BIOS_DMI_FALLBACK),VBOX_BIOS_DMI_FALLBACK,) \
VBOX_WITH_DMI_CHASSIS \
VBOX_WITH_DMI_OEMSTRINGS \
- $(if $(VBOX_WITH_NEW_LPC_DEVICE),VBOX_WITH_NEW_LPC_DEVICE,) \
- $(if $(VBOX_WITH_NEW_SERIAL),VBOX_WITH_NEW_SERIAL,)
+ $(if $(VBOX_WITH_NEW_LPC_DEVICE),VBOX_WITH_NEW_LPC_DEVICE,)
VBoxDD_DEFS.win = _WIN32_WINNT=0x0510
ifeq ($(KBUILD_TARGET_ARCH),x86)
VBoxDD_DEFS.darwin = VBOX_WITH_2X_4GB_ADDR_SPACE
@@ -177,6 +176,11 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Network/DrvDedicatedNic.cpp \
PC/DrvACPI.cpp \
PC/DrvAcpiCpu.cpp \
+ Serial/DevSerial.cpp \
+ Serial/DevOxPcie958.cpp \
+ Serial/UartCore.cpp \
+ Serial/DrvChar.cpp \
+ Serial/DrvHostSerial.cpp \
Serial/DrvNamedPipe.cpp \
Serial/DrvTCP.cpp \
Serial/DrvRawFile.cpp \
@@ -196,22 +200,6 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
VBoxDD_SOURCES += Storage/DrvHostFloppy.cpp
endif
- if defined(VBOX_WITH_NEW_SERIAL)
- VBoxDD_SOURCES += \
- Serial/DevSerialNew.cpp \
- Serial/DevOxPcie958.cpp \
- Serial/UartCore.cpp \
- Serial/DrvCharNew.cpp \
- Serial/DrvHostSerialNew.cpp
- else
- VBoxDD_SOURCES += \
- Serial/DevSerial.cpp \
- Serial/DrvChar.cpp
- ifn1of ($(KBUILD_TARGET), os2)
- VBoxDD_SOURCES += \
- Serial/DrvHostSerial.cpp
- endif
- endif
ifn1of ($(KBUILD_TARGET), darwin)
VBoxDD_SOURCES += Storage/HBDMgmt-generic.cpp
@@ -918,6 +906,8 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Storage/DevATA.cpp \
Network/DevPCNet.cpp \
Serial/DevSerial.cpp \
+ Serial/DevOxPcie958.cpp \
+ Serial/UartCore.cpp \
Parallel/DevParallel.cpp \
VMMDev/VMMDevTesting.cpp
@@ -1021,14 +1011,6 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Storage/DevNVMe.cpp
endif
- if defined(VBOX_WITH_NEW_SERIAL)
- VBoxDDRC_SOURCES := \
- $(filter-out Serial/DevSerial.cpp, $(VBoxDDRC_SOURCES)) \
- Serial/DevSerialNew.cpp \
- Serial/DevOxPcie958.cpp \
- Serial/UartCore.cpp
- endif
-
if1of ($(VBOX_LDR_FMT32), pe lx)
VBoxDDRC_LIBS = \
$(PATH_STAGE_LIB)/VMMRCBuiltin$(VBOX_SUFF_LIB) \
@@ -1097,6 +1079,8 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Storage/DevATA.cpp \
Network/DevPCNet.cpp \
Serial/DevSerial.cpp \
+ Serial/DevOxPcie958.cpp \
+ Serial/UartCore.cpp \
Parallel/DevParallel.cpp \
VMMDev/VMMDevTesting.cpp \
Network/DrvIntNet.cpp \
@@ -1198,14 +1182,6 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Storage/DevNVMe.cpp
endif
- if defined(VBOX_WITH_NEW_SERIAL)
- VBoxDDR0_SOURCES := \
- $(filter-out Serial/DevSerial.cpp, $(VBoxDDR0_SOURCES)) \
- Serial/DevSerialNew.cpp \
- Serial/DevOxPcie958.cpp \
- Serial/UartCore.cpp
- endif
-
ifdef VBOX_WITH_HGSMI
VBoxDDR0_DEFS += VBOX_WITH_HGSMI
endif
diff --git a/src/VBox/Devices/Serial/DevSerial.cpp b/src/VBox/Devices/Serial/DevSerial.cpp
index ce0baf67f60..b8c90029088 100644
--- a/src/VBox/Devices/Serial/DevSerial.cpp
+++ b/src/VBox/Devices/Serial/DevSerial.cpp
@@ -1,11 +1,12 @@
/* $Id$ */
/** @file
* DevSerial - 16550A UART emulation.
- * (taken from hw/serial.c 2010/05/15 with modifications)
+ *
+ * The documentation for this device was taken from the PC16550D spec from TI.
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -16,39 +17,14 @@
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-/*
- * This code is based on:
- *
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
/*********************************************************************************************************************************
* Header Files *
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_SERIAL
#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdmserialifs.h>
+#include <VBox/vmm/vm.h>
#include <iprt/assert.h>
#include <iprt/uuid.h>
#include <iprt/string.h>
@@ -56,116 +32,23 @@
#include <iprt/critsect.h>
#include "VBoxDD.h"
-
-#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
-
-#ifdef VBOX_SERIAL_PCI
-# include <VBox/pci.h>
-#endif /* VBOX_SERIAL_PCI */
+#include "UartCore.h"
/*********************************************************************************************************************************
* Defined Constants And Macros *
*********************************************************************************************************************************/
-#define SERIAL_SAVED_STATE_VERSION_16450 3
-#define SERIAL_SAVED_STATE_VERSION_MISSING_BITS 4
-#define SERIAL_SAVED_STATE_VERSION 5
-
-#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
-
-#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
-#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
-#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
-#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
-
-#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
-#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
-
-#define UART_IIR_MSI 0x00 /* Modem status interrupt */
-#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
-#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
-#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
-#define UART_IIR_CTI 0x0C /* Character Timeout Indication */
-
-#define UART_IIR_FENF 0x80 /* Fifo enabled, but not functioning */
-#define UART_IIR_FE 0xC0 /* Fifo enabled */
-
-/*
- * These are the definitions for the Modem Control Register
- */
-#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
-#define UART_MCR_OUT2 0x08 /* Out2 complement */
-#define UART_MCR_OUT1 0x04 /* Out1 complement */
-#define UART_MCR_RTS 0x02 /* RTS complement */
-#define UART_MCR_DTR 0x01 /* DTR complement */
-
-/*
- * These are the definitions for the Modem Status Register
- */
-#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
-#define UART_MSR_RI 0x40 /* Ring Indicator */
-#define UART_MSR_DSR 0x20 /* Data Set Ready */
-#define UART_MSR_CTS 0x10 /* Clear to Send */
-#define UART_MSR_DDCD 0x08 /* Delta DCD */
-#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
-#define UART_MSR_DDSR 0x02 /* Delta DSR */
-#define UART_MSR_DCTS 0x01 /* Delta CTS */
-#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
-
-#define UART_LSR_TEMT 0x40 /* Transmitter empty */
-#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
-#define UART_LSR_BI 0x10 /* Break interrupt indicator */
-#define UART_LSR_FE 0x08 /* Frame error indicator */
-#define UART_LSR_PE 0x04 /* Parity error indicator */
-#define UART_LSR_OE 0x02 /* Overrun error indicator */
-#define UART_LSR_DR 0x01 /* Receiver data ready */
-#define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */
-
-/*
- * Interrupt trigger levels.
- * The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher.
- */
-#define UART_FCR_ITL_1 0x00 /* 1 byte ITL */
-#define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */
-#define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */
-#define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */
-
-#define UART_FCR_DMS 0x08 /* DMA Mode Select */
-#define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */
-#define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */
-#define UART_FCR_FE 0x01 /* FIFO Enable */
-
-#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
-
-#define XMIT_FIFO 0
-#define RECV_FIFO 1
-#define MIN_XMIT_RETRY 16
-#define MAX_XMIT_RETRY_TIME 1 /* max time (in seconds) for retrying the character xmit before dropping it */
/*********************************************************************************************************************************
* Structures and Typedefs *
*********************************************************************************************************************************/
-struct SerialFifo
-{
- uint8_t data[UART_FIFO_LENGTH];
- uint8_t count;
- uint8_t itl;
- uint8_t tail;
- uint8_t head;
-};
-
/**
* Serial device.
- *
- * @implements PDMIBASE
- * @implements PDMICHARPORT
*/
-typedef struct SerialState
+typedef struct DEVSERIAL
{
- /** Access critical section. */
- PDMCRITSECT CritSect;
/** Pointer to the device instance - R3 Ptr. */
PPDMDEVINSR3 pDevInsR3;
/** Pointer to the device instance - R0 Ptr. */
@@ -174,743 +57,106 @@ typedef struct SerialState
PPDMDEVINSRC pDevInsRC;
/** Alignment. */
RTRCPTR Alignment0;
- /** LUN\#0: The base interface. */
- PDMIBASE IBase;
- /** LUN\#0: The character port interface. */
- PDMICHARPORT ICharPort;
- /** Pointer to the attached base driver. */
- R3PTRTYPE(PPDMIBASE) pDrvBase;
- /** Pointer to the attached character driver. */
- R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar;
-
- RTSEMEVENT ReceiveSem;
- PTMTIMERR3 fifo_timeout_timer;
- PTMTIMERR3 transmit_timerR3;
- PTMTIMERR0 transmit_timerR0; /* currently not used */
- PTMTIMERRC transmit_timerRC; /* currently not used */
- RTRCPTR Alignment1;
- SerialFifo recv_fifo;
- SerialFifo xmit_fifo;
-
- uint32_t base;
- uint16_t divider;
- uint16_t Alignment2[1];
- uint8_t rbr; /**< receive register */
- uint8_t thr; /**< transmit holding register */
- uint8_t tsr; /**< transmit shift register */
- uint8_t ier; /**< interrupt enable register */
- uint8_t iir; /**< interrupt identification register, R/O */
- uint8_t lcr; /**< line control register */
- uint8_t mcr; /**< modem control register */
- uint8_t lsr; /**< line status register, R/O */
- uint8_t msr; /**< modem status register, R/O */
- uint8_t scr; /**< scratch register */
- uint8_t fcr; /**< fifo control register */
- uint8_t fcr_vmstate;
- /* NOTE: this hidden state is necessary for tx irq generation as
- it can be reset while reading iir */
- int thr_ipending;
- int timeout_ipending;
- int irq;
- int last_break_enable;
- /** Counter for retrying xmit */
- int tsr_retry;
- int tsr_retry_bound; /**< number of retries before dropping a character */
- int tsr_retry_bound_max; /**< maximum possible tsr_retry_bound value that can be set while dynamic bound adjustment */
- int tsr_retry_bound_min; /**< minimum possible tsr_retry_bound value that can be set while dynamic bound adjustment */
- bool msr_changed;
- bool fGCEnabled;
+ /** Flag whether the R0 portion of this device is enabled. */
bool fR0Enabled;
- bool fYieldOnLSRRead;
- bool volatile fRecvWaiting;
- bool f16550AEnabled;
- bool Alignment3[6];
- /** Time it takes to transmit a character */
- uint64_t char_transmit_time;
-
-#ifdef VBOX_SERIAL_PCI
- PDMPCIDEV PciDev;
-#endif /* VBOX_SERIAL_PCI */
+ /** Flag whether the RC portion of this device is enabled. */
+ bool fRCEnabled;
+ /** Alignment. */
+ bool afAlignment1[2];
+ /** The IRQ value. */
+ uint8_t uIrq;
+ /** The base I/O port the device is registered at. */
+ RTIOPORT PortBase;
+
+ /** The UART core. */
+ UARTCORE UartCore;
} DEVSERIAL;
/** Pointer to the serial device state. */
typedef DEVSERIAL *PDEVSERIAL;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-#ifdef IN_RING3
-
-static int serial_can_receive(PDEVSERIAL pThis);
-static void serial_receive(PDEVSERIAL pThis, const uint8_t *buf, int size);
-
-static void fifo_clear(PDEVSERIAL pThis, int fifo)
-{
- SerialFifo *f = (fifo) ? &pThis->recv_fifo : &pThis->xmit_fifo;
- memset(f->data, 0, UART_FIFO_LENGTH);
- f->count = 0;
- f->head = 0;
- f->tail = 0;
-}
-
-static int fifo_put(PDEVSERIAL pThis, int fifo, uint8_t chr)
-{
- SerialFifo *f = (fifo) ? &pThis->recv_fifo : &pThis->xmit_fifo;
-
- /* Receive overruns do not overwrite FIFO contents. */
- if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH)
- {
- f->data[f->head++] = chr;
- if (f->head == UART_FIFO_LENGTH)
- f->head = 0;
- }
-
- if (f->count < UART_FIFO_LENGTH)
- f->count++;
- else if (fifo == XMIT_FIFO) /* need to at least adjust tail to maintain pipe state consistency */
- ++f->tail;
- else if (fifo == RECV_FIFO)
- pThis->lsr |= UART_LSR_OE;
-
- return 1;
-}
-
-static uint8_t fifo_get(PDEVSERIAL pThis, int fifo)
-{
- SerialFifo *f = (fifo) ? &pThis->recv_fifo : &pThis->xmit_fifo;
- uint8_t c;
-
- if (f->count == 0)
- return 0;
-
- c = f->data[f->tail++];
- if (f->tail == UART_FIFO_LENGTH)
- f->tail = 0;
- f->count--;
-
- return c;
-}
-
-static void serial_update_irq(PDEVSERIAL pThis)
-{
- uint8_t tmp_iir = UART_IIR_NO_INT;
-
- if ( (pThis->ier & UART_IER_RLSI)
- && (pThis->lsr & UART_LSR_INT_ANY)) {
- tmp_iir = UART_IIR_RLSI;
- } else if ((pThis->ier & UART_IER_RDI) && pThis->timeout_ipending) {
- /* Note that(pThis->ier & UART_IER_RDI) can mask this interrupt,
- * this is not in the specification but is observed on existing
- * hardware. */
- tmp_iir = UART_IIR_CTI;
- } else if ( (pThis->ier & UART_IER_RDI)
- && (pThis->lsr & UART_LSR_DR)
- && ( !(pThis->fcr & UART_FCR_FE)
- || pThis->recv_fifo.count >= pThis->recv_fifo.itl)) {
- tmp_iir = UART_IIR_RDI;
- } else if ( (pThis->ier & UART_IER_THRI)
- && pThis->thr_ipending) {
- tmp_iir = UART_IIR_THRI;
- } else if ( (pThis->ier & UART_IER_MSI)
- && (pThis->msr & UART_MSR_ANY_DELTA)) {
- tmp_iir = UART_IIR_MSI;
- }
- pThis->iir = tmp_iir | (pThis->iir & 0xF0);
-
- /** XXX only call the SetIrq function if the state really changes! */
- if (tmp_iir != UART_IIR_NO_INT) {
- Log(("serial_update_irq %d 1\n", pThis->irq));
-# ifdef VBOX_SERIAL_PCI
- PDMDevHlpPCISetIrqNoWait(pThis->CTX_SUFF(pDevIns), 0, 1);
-# else /* !VBOX_SERIAL_PCI */
- PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->irq, 1);
-# endif /* !VBOX_SERIAL_PCI */
- } else {
- Log(("serial_update_irq %d 0\n", pThis->irq));
-# ifdef VBOX_SERIAL_PCI
- PDMDevHlpPCISetIrqNoWait(pThis->CTX_SUFF(pDevIns), 0, 0);
-# else /* !VBOX_SERIAL_PCI */
- PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->irq, 0);
-# endif /* !VBOX_SERIAL_PCI */
- }
-}
-
-static void serial_tsr_retry_update_parameters(PDEVSERIAL pThis, uint64_t tf)
-{
- pThis->tsr_retry_bound_max = RT_MAX((tf * MAX_XMIT_RETRY_TIME) / pThis->char_transmit_time, MIN_XMIT_RETRY);
- pThis->tsr_retry_bound_min = RT_MAX(pThis->tsr_retry_bound_max / (1000 * MAX_XMIT_RETRY_TIME), MIN_XMIT_RETRY);
- /* for simplicity just reset to max retry count */
- pThis->tsr_retry_bound = pThis->tsr_retry_bound_max;
-}
-
-static void serial_tsr_retry_bound_reached(PDEVSERIAL pThis)
-{
- /* this is most likely means we have some backend connection issues */
- /* decrement the retry bound */
- pThis->tsr_retry_bound = RT_MAX(pThis->tsr_retry_bound / (10 * MAX_XMIT_RETRY_TIME), pThis->tsr_retry_bound_min);
-}
-
-static void serial_tsr_retry_succeeded(PDEVSERIAL pThis)
-{
- /* success means we have a backend connection working OK,
- * set retry bound to its maximum value */
- pThis->tsr_retry_bound = pThis->tsr_retry_bound_max;
-}
-static void serial_update_parameters(PDEVSERIAL pThis)
-{
- int speed, parity, data_bits, stop_bits, frame_size;
-
- if (pThis->divider == 0)
- return;
-
- frame_size = 1;
- if (pThis->lcr & 0x08) {
- frame_size++;
- if (pThis->lcr & 0x10)
- parity = 'E';
- else
- parity = 'O';
- } else {
- parity = 'N';
- }
- if (pThis->lcr & 0x04)
- stop_bits = 2;
- else
- stop_bits = 1;
-
- data_bits = (pThis->lcr & 0x03) + 5;
- frame_size += data_bits + stop_bits;
- speed = 115200 / pThis->divider;
- uint64_t tf = TMTimerGetFreq(CTX_SUFF(pThis->transmit_timer));
- pThis->char_transmit_time = (tf / speed) * frame_size;
- serial_tsr_retry_update_parameters(pThis, tf);
-
- Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
-
- if (RT_LIKELY(pThis->pDrvChar))
- pThis->pDrvChar->pfnSetParameters(pThis->pDrvChar, speed, parity, data_bits, stop_bits);
-}
-
-static void serial_xmit(PDEVSERIAL pThis, bool bRetryXmit)
-{
- if (pThis->tsr_retry <= 0) {
- if (pThis->fcr & UART_FCR_FE) {
- pThis->tsr = fifo_get(pThis, XMIT_FIFO);
- if (!pThis->xmit_fifo.count)
- pThis->lsr |= UART_LSR_THRE;
- } else {
- pThis->tsr = pThis->thr;
- pThis->lsr |= UART_LSR_THRE;
- }
- }
-
- if (pThis->mcr & UART_MCR_LOOP) {
- /* in loopback mode, say that we just received a char */
- serial_receive(pThis, &pThis->tsr, 1);
- } else if ( RT_LIKELY(pThis->pDrvChar)
- && RT_FAILURE(pThis->pDrvChar->pfnWrite(pThis->pDrvChar, &pThis->tsr, 1))) {
- if ((pThis->tsr_retry >= 0) && ((!bRetryXmit) || (pThis->tsr_retry <= pThis->tsr_retry_bound))) {
- if (!pThis->tsr_retry)
- pThis->tsr_retry = 1; /* make sure the retry state is always set */
- else if (bRetryXmit) /* do not increase the retry count if the retry is actually caused by next char write */
- pThis->tsr_retry++;
-
- TMTimerSet(CTX_SUFF(pThis->transmit_timer), TMTimerGet(CTX_SUFF(pThis->transmit_timer)) + pThis->char_transmit_time * 4);
- return;
- } else {
- /* drop this character. */
- pThis->tsr_retry = 0;
- serial_tsr_retry_bound_reached(pThis);
- }
- }
- else {
- pThis->tsr_retry = 0;
- serial_tsr_retry_succeeded(pThis);
- }
-
- if (!(pThis->lsr & UART_LSR_THRE))
- TMTimerSet(CTX_SUFF(pThis->transmit_timer),
- TMTimerGet(CTX_SUFF(pThis->transmit_timer)) + pThis->char_transmit_time);
-
- if (pThis->lsr & UART_LSR_THRE) {
- pThis->lsr |= UART_LSR_TEMT;
- pThis->thr_ipending = 1;
- serial_update_irq(pThis);
- }
-}
-
-#endif /* IN_RING3 */
-
-static int serial_ioport_write(PDEVSERIAL pThis, uint32_t addr, uint32_t val)
-{
-#ifndef IN_RING3
- NOREF(pThis); RT_NOREF_PV(addr); RT_NOREF_PV(val);
- return VINF_IOM_R3_IOPORT_WRITE;
-#else
- addr &= 7;
- switch(addr) {
- default:
- case 0:
- if (pThis->lcr & UART_LCR_DLAB) {
- pThis->divider = (pThis->divider & 0xff00) | val;
- serial_update_parameters(pThis);
- } else {
- pThis->thr = (uint8_t) val;
- if (pThis->fcr & UART_FCR_FE) {
- fifo_put(pThis, XMIT_FIFO, pThis->thr);
- pThis->thr_ipending = 0;
- pThis->lsr &= ~UART_LSR_TEMT;
- pThis->lsr &= ~UART_LSR_THRE;
- serial_update_irq(pThis);
- } else {
- pThis->thr_ipending = 0;
- pThis->lsr &= ~UART_LSR_THRE;
- serial_update_irq(pThis);
- }
- serial_xmit(pThis, false);
- }
- break;
- case 1:
- if (pThis->lcr & UART_LCR_DLAB) {
- pThis->divider = (pThis->divider & 0x00ff) | (val << 8);
- serial_update_parameters(pThis);
- } else {
- pThis->ier = val & 0x0f;
- if (pThis->lsr & UART_LSR_THRE) {
- pThis->thr_ipending = 1;
- serial_update_irq(pThis);
- }
- }
- break;
- case 2:
- if (!pThis->f16550AEnabled)
- break;
-
- val = val & 0xFF;
-
- if (pThis->fcr == val)
- break;
-
- /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
- if ((val ^ pThis->fcr) & UART_FCR_FE)
- val |= UART_FCR_XFR | UART_FCR_RFR;
-
- /* FIFO clear */
- if (val & UART_FCR_RFR) {
- TMTimerStop(pThis->fifo_timeout_timer);
- pThis->timeout_ipending = 0;
- fifo_clear(pThis, RECV_FIFO);
- }
- if (val & UART_FCR_XFR) {
- fifo_clear(pThis, XMIT_FIFO);
- }
-
- if (val & UART_FCR_FE) {
- pThis->iir |= UART_IIR_FE;
- /* Set RECV_FIFO trigger Level */
- switch (val & 0xC0) {
- case UART_FCR_ITL_1:
- pThis->recv_fifo.itl = 1;
- break;
- case UART_FCR_ITL_2:
- pThis->recv_fifo.itl = 4;
- break;
- case UART_FCR_ITL_3:
- pThis->recv_fifo.itl = 8;
- break;
- case UART_FCR_ITL_4:
- pThis->recv_fifo.itl = 14;
- break;
- }
- } else
- pThis->iir &= ~UART_IIR_FE;
-
- /* Set fcr - or at least the bits in it that are supposed to "stick" */
- pThis->fcr = val & 0xC9;
- serial_update_irq(pThis);
- break;
- case 3:
- {
- int break_enable;
- pThis->lcr = val;
- serial_update_parameters(pThis);
- break_enable = (val >> 6) & 1;
- if (break_enable != pThis->last_break_enable) {
- pThis->last_break_enable = break_enable;
- if (RT_LIKELY(pThis->pDrvChar))
- {
- Log(("serial_ioport_write: Set break %d\n", break_enable));
- int rc = pThis->pDrvChar->pfnSetBreak(pThis->pDrvChar, !!break_enable);
- AssertRC(rc);
- }
- }
- }
- break;
- case 4:
- pThis->mcr = val & 0x1f;
- if (RT_LIKELY(pThis->pDrvChar))
- {
- int rc = pThis->pDrvChar->pfnSetModemLines(pThis->pDrvChar,
- !!(pThis->mcr & UART_MCR_RTS),
- !!(pThis->mcr & UART_MCR_DTR));
- AssertRC(rc);
- }
- break;
- case 5:
- break;
- case 6:
- break;
- case 7:
- pThis->scr = val;
- break;
- }
- return VINF_SUCCESS;
-#endif
-}
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
-static uint32_t serial_ioport_read(PDEVSERIAL pThis, uint32_t addr, int *pRC)
-{
- uint32_t ret = ~0U;
-
- *pRC = VINF_SUCCESS;
-
- addr &= 7;
- switch(addr) {
- default:
- case 0:
- if (pThis->lcr & UART_LCR_DLAB) {
- /* DLAB == 1: divisor latch (LS) */
- ret = pThis->divider & 0xff;
- } else {
-#ifndef IN_RING3
- *pRC = VINF_IOM_R3_IOPORT_READ;
-#else
- if (pThis->fcr & UART_FCR_FE) {
- ret = fifo_get(pThis, RECV_FIFO);
- if (pThis->recv_fifo.count == 0)
- pThis->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
- else
- TMTimerSet(pThis->fifo_timeout_timer,
- TMTimerGet(pThis->fifo_timeout_timer) + pThis->char_transmit_time * 4);
- pThis->timeout_ipending = 0;
- } else {
- Log(("serial_io_port_read: read 0x%X\n", pThis->rbr));
- ret = pThis->rbr;
- pThis->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
- }
- serial_update_irq(pThis);
- if (pThis->fRecvWaiting)
- {
- pThis->fRecvWaiting = false;
- int rc = RTSemEventSignal(pThis->ReceiveSem);
- AssertRC(rc);
- }
-#endif
- }
- break;
- case 1:
- if (pThis->lcr & UART_LCR_DLAB) {
- /* DLAB == 1: divisor latch (MS) */
- ret = (pThis->divider >> 8) & 0xff;
- } else {
- ret = pThis->ier;
- }
- break;
- case 2:
-#ifndef IN_RING3
- *pRC = VINF_IOM_R3_IOPORT_READ;
-#else
- ret = pThis->iir;
- if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
- pThis->thr_ipending = 0;
- serial_update_irq(pThis);
- }
- /* reset msr changed bit */
- pThis->msr_changed = false;
-#endif
- break;
- case 3:
- ret = pThis->lcr;
- break;
- case 4:
- ret = pThis->mcr;
- break;
- case 5:
- if ((pThis->lsr & UART_LSR_DR) == 0 && pThis->fYieldOnLSRRead)
- {
- /* No data available and yielding is enabled, so yield in ring3. */
-#ifndef IN_RING3
- *pRC = VINF_IOM_R3_IOPORT_READ;
- break;
-#else
- RTThreadYield ();
-#endif
- }
- ret = pThis->lsr;
- /* Clear break and overrun interrupts */
- if (pThis->lsr & (UART_LSR_BI|UART_LSR_OE)) {
-#ifndef IN_RING3
- *pRC = VINF_IOM_R3_IOPORT_READ;
-#else
- pThis->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
- serial_update_irq(pThis);
-#endif
- }
- break;
- case 6:
- if (pThis->mcr & UART_MCR_LOOP) {
- /* in loopback, the modem output pins are connected to the
- inputs */
- ret = (pThis->mcr & 0x0c) << 4;
- ret |= (pThis->mcr & 0x02) << 3;
- ret |= (pThis->mcr & 0x01) << 5;
- } else {
- ret = pThis->msr;
- /* Clear delta bits & msr int after read, if they were set */
- if (pThis->msr & UART_MSR_ANY_DELTA) {
-#ifndef IN_RING3
- *pRC = VINF_IOM_R3_IOPORT_READ;
-#else
- pThis->msr &= 0xF0;
- serial_update_irq(pThis);
-#endif
- }
- }
- break;
- case 7:
- ret = pThis->scr;
- break;
- }
- return ret;
-}
-#ifdef IN_RING3
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
-static int serial_can_receive(PDEVSERIAL pThis)
-{
- if (pThis->fcr & UART_FCR_FE) {
- if (pThis->recv_fifo.count < UART_FIFO_LENGTH)
- return (pThis->recv_fifo.count <= pThis->recv_fifo.itl)
- ? pThis->recv_fifo.itl - pThis->recv_fifo.count : 1;
- else
- return 0;
- } else {
- return !(pThis->lsr & UART_LSR_DR);
- }
-}
-static void serial_receive(PDEVSERIAL pThis, const uint8_t *buf, int size)
+PDMBOTHCBDECL(void) serialIrqReq(PPDMDEVINS pDevIns, PUARTCORE pUart, unsigned iLUN, int iLvl)
{
- if (pThis->fcr & UART_FCR_FE) {
- int i;
- for (i = 0; i < size; i++) {
- fifo_put(pThis, RECV_FIFO, buf[i]);
- }
- pThis->lsr |= UART_LSR_DR;
- /* call the timeout receive callback in 4 char transmit time */
- TMTimerSet(pThis->fifo_timeout_timer, TMTimerGet(pThis->fifo_timeout_timer) + pThis->char_transmit_time * 4);
- } else {
- if (pThis->lsr & UART_LSR_DR)
- pThis->lsr |= UART_LSR_OE;
- pThis->rbr = buf[0];
- pThis->lsr |= UART_LSR_DR;
- }
- serial_update_irq(pThis);
+ RT_NOREF(pUart, iLUN);
+ PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
+ PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
}
-/**
- * @interface_method_impl{PDMICHARPORT,pfnNotifyRead}
- */
-static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
-{
- PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ICharPort);
- const uint8_t *pu8Buf = (const uint8_t*)pvBuf;
- size_t cbRead = *pcbRead;
-
- PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
- for (; cbRead > 0; cbRead--, pu8Buf++)
- {
- if (!serial_can_receive(pThis))
- {
- /* If we cannot receive then wait for not more than 250ms. If we still
- * cannot receive then the new character will either overwrite rbr
- * or it will be dropped at fifo_put(). */
- pThis->fRecvWaiting = true;
- PDMCritSectLeave(&pThis->CritSect);
- RTSemEventWait(pThis->ReceiveSem, 250);
- PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
- }
- serial_receive(pThis, &pu8Buf[0], 1);
- }
- PDMCritSectLeave(&pThis->CritSect);
- return VINF_SUCCESS;
-}
+/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
/**
- * @@interface_method_impl{PDMICHARPORT,pfnNotifyStatusLinesChanged}
+ * @callback_method_impl{FNIOMIOPORTOUT}
*/
-static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
+PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
{
- PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ICharPort);
- uint8_t newMsr = 0;
-
- Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
-
- PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
-
- /* Set new states. */
- if (newStatusLines & PDMICHARPORT_STATUS_LINES_DCD)
- newMsr |= UART_MSR_DCD;
- if (newStatusLines & PDMICHARPORT_STATUS_LINES_RI)
- newMsr |= UART_MSR_RI;
- if (newStatusLines & PDMICHARPORT_STATUS_LINES_DSR)
- newMsr |= UART_MSR_DSR;
- if (newStatusLines & PDMICHARPORT_STATUS_LINES_CTS)
- newMsr |= UART_MSR_CTS;
-
- /* Compare the old and the new states and set the delta bits accordingly. */
- if ((newMsr & UART_MSR_DCD) != (pThis->msr & UART_MSR_DCD))
- newMsr |= UART_MSR_DDCD;
- if ((newMsr & UART_MSR_RI) != 0 && (pThis->msr & UART_MSR_RI) == 0)
- newMsr |= UART_MSR_TERI;
- if ((newMsr & UART_MSR_DSR) != (pThis->msr & UART_MSR_DSR))
- newMsr |= UART_MSR_DDSR;
- if ((newMsr & UART_MSR_CTS) != (pThis->msr & UART_MSR_CTS))
- newMsr |= UART_MSR_DCTS;
-
- pThis->msr = newMsr;
- pThis->msr_changed = true;
- serial_update_irq(pThis);
-
- PDMCritSectLeave(&pThis->CritSect);
+ PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
+ RT_NOREF_PV(pvUser);
- return VINF_SUCCESS;
+ return uartRegWrite(&pThis->UartCore, uPort - pThis->PortBase, u32, cb);
}
/**
- * @interface_method_impl{PDMICHARPORT,pfnNotifyBufferFull}
- */
-static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull)
-{
- RT_NOREF(pInterface, fFull);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMICHARPORT,pfnNotifyBreak}
+ * @callback_method_impl{FNIOMIOPORTIN}
*/
-static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface)
+PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
{
- PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, ICharPort);
-
- Log(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
-
- PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
-
- pThis->lsr |= UART_LSR_BI;
- serial_update_irq(pThis);
-
- PDMCritSectLeave(&pThis->CritSect);
+ PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
+ RT_NOREF_PV(pvUser);
- return VINF_SUCCESS;
+ return uartRegRead(&pThis->UartCore, uPort - pThis->PortBase, pu32, cb);
}
-/* -=-=-=-=-=-=-=-=- Timer callbacks -=-=-=-=-=-=-=-=- */
+#ifdef IN_RING3
-/**
- * @callback_method_impl{FNTMTIMERDEV, Fifo timer function.}
- */
-static DECLCALLBACK(void) serialFifoTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
-{
- RT_NOREF(pDevIns, pTimer);
- PDEVSERIAL pThis = (PDEVSERIAL)pvUser;
- Assert(PDMCritSectIsOwner(&pThis->CritSect));
- if (pThis->recv_fifo.count)
- {
- pThis->timeout_ipending = 1;
- serial_update_irq(pThis);
- }
-}
/**
- * @callback_method_impl{FNTMTIMERDEV, Transmit timer function.}
+ * Returns the matching UART type from the given string.
*
- * Just retry to transmit a character.
+ * @returns UART type based on the given string or UARTTYPE_INVALID if an invalid type was passed.
+ * @param pszUartType The UART type.
*/
-static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
+static UARTTYPE serialR3GetUartTypeFromString(const char *pszUartType)
{
- RT_NOREF(pDevIns, pTimer);
- PDEVSERIAL pThis = (PDEVSERIAL)pvUser;
- Assert(PDMCritSectIsOwner(&pThis->CritSect));
- serial_xmit(pThis, true);
-}
+ if (!RTStrCmp(pszUartType, "16450"))
+ return UARTTYPE_16450;
+ else if (!RTStrCmp(pszUartType, "16550A"))
+ return UARTTYPE_16550A;
+ else if (!RTStrCmp(pszUartType, "16750"))
+ return UARTTYPE_16750;
-#endif /* IN_RING3 */
-
-/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
-
-/**
- * @callback_method_impl{FNIOMIOPORTOUT}
- */
-PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- int rc;
- Assert(PDMCritSectIsOwner(&pThis->CritSect));
- RT_NOREF_PV(pvUser);
-
- if (cb == 1)
- {
- Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, uPort, u32));
- rc = serial_ioport_write(pThis, uPort, u32);
- }
- else
- {
- AssertMsgFailed(("uPort=%#x cb=%d u32=%#x\n", uPort, cb, u32));
- rc = VINF_SUCCESS;
- }
-
- return rc;
+ AssertLogRelMsgFailedReturn(("Unknown UART type \"%s\" specified", pszUartType),
+ UARTTYPE_INVALID);
}
-/**
- * @callback_method_impl{FNIOMIOPORTIN}
- */
-PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- int rc;
- Assert(PDMCritSectIsOwner(&pThis->CritSect));
- RT_NOREF_PV(pvUser);
-
- if (cb == 1)
- {
- *pu32 = serial_ioport_read(pThis, uPort, &rc);
- Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, uPort, *pu32));
- }
- else
- rc = VERR_IOM_IOPORT_UNUSED;
-
- return rc;
-}
-
-#ifdef IN_RING3
-
/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
/**
* @callback_method_impl{FNSSMDEVLIVEEXEC}
*/
-static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
+static DECLCALLBACK(int) serialR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
{
RT_NOREF(uPass);
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- SSMR3PutS32(pSSM, pThis->irq);
- SSMR3PutU32(pSSM, pThis->base);
+ SSMR3PutU8(pSSM, pThis->uIrq);
+ SSMR3PutIOPort(pSSM, pThis->PortBase);
+ SSMR3PutU32(pSSM, pThis->UartCore.enmType);
+
return VINF_SSM_DONT_CALL_AGAIN;
}
@@ -918,41 +164,15 @@ static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
/**
* @callback_method_impl{FNSSMDEVSAVEEXEC}
*/
-static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+static DECLCALLBACK(int) serialR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- SSMR3PutU16(pSSM, pThis->divider);
- SSMR3PutU8(pSSM, pThis->rbr);
- SSMR3PutU8(pSSM, pThis->ier);
- SSMR3PutU8(pSSM, pThis->lcr);
- SSMR3PutU8(pSSM, pThis->mcr);
- SSMR3PutU8(pSSM, pThis->lsr);
- SSMR3PutU8(pSSM, pThis->msr);
- SSMR3PutU8(pSSM, pThis->scr);
- SSMR3PutU8(pSSM, pThis->fcr); /* 16550A */
- SSMR3PutS32(pSSM, pThis->thr_ipending);
- SSMR3PutS32(pSSM, pThis->irq);
- SSMR3PutS32(pSSM, pThis->last_break_enable);
- SSMR3PutU32(pSSM, pThis->base);
- SSMR3PutBool(pSSM, pThis->msr_changed);
-
- /* Version 5, safe everything that might be of importance. Much better than
- missing relevant bits! */
- SSMR3PutU8(pSSM, pThis->thr);
- SSMR3PutU8(pSSM, pThis->tsr);
- SSMR3PutU8(pSSM, pThis->iir);
- SSMR3PutS32(pSSM, pThis->timeout_ipending);
- TMR3TimerSave(pThis->fifo_timeout_timer, pSSM);
- TMR3TimerSave(pThis->transmit_timerR3, pSSM);
- SSMR3PutU8(pSSM, pThis->recv_fifo.itl);
- SSMR3PutU8(pSSM, pThis->xmit_fifo.itl);
-
- /* Don't store:
- * - the content of the FIFO
- * - tsr_retry
- */
+ SSMR3PutU8( pSSM, pThis->uIrq);
+ SSMR3PutIOPort(pSSM, pThis->PortBase);
+ SSMR3PutU32( pSSM, pThis->UartCore.enmType);
+ uartR3SaveExec(&pThis->UartCore, pSSM);
return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
}
@@ -960,133 +180,73 @@ static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
/**
* @callback_method_impl{FNSSMDEVLOADEXEC}
*/
-static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+static DECLCALLBACK(int) serialR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- int32_t iIrq;
- uint32_t IOBase;
+ PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
+ uint8_t uIrq;
+ RTIOPORT PortBase;
+ UARTTYPE enmType;
- AssertMsgReturn(uVersion >= SERIAL_SAVED_STATE_VERSION_16450, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
+ AssertMsgReturn(uVersion >= UART_SAVED_STATE_VERSION_16450, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
if (uPass != SSM_PASS_FINAL)
{
- SSMR3GetS32(pSSM, &iIrq);
- int rc = SSMR3GetU32(pSSM, &IOBase);
+ SSMR3GetU8(pSSM, &uIrq);
+ SSMR3GetIOPort(pSSM, &PortBase);
+ int rc = SSMR3GetU32(pSSM, (uint32_t *)&enmType);
AssertRCReturn(rc, rc);
}
else
{
- if (uVersion == SERIAL_SAVED_STATE_VERSION_16450)
+ int rc = VINF_SUCCESS;
+
+ if (uVersion > UART_SAVED_STATE_VERSION_LEGACY_CODE)
{
- pThis->f16550AEnabled = false;
- LogRel(("Serial#%d: falling back to 16450 mode from load state\n", pDevIns->iInstance));
+ SSMR3GetU8( pSSM, &uIrq);
+ SSMR3GetIOPort(pSSM, &PortBase);
+ SSMR3GetU32( pSSM, (uint32_t *)&enmType);
+ rc = uartR3LoadExec(&pThis->UartCore, pSSM, uVersion, uPass, NULL, NULL);
}
-
- SSMR3GetU16(pSSM, &pThis->divider);
- SSMR3GetU8(pSSM, &pThis->rbr);
- SSMR3GetU8(pSSM, &pThis->ier);
- SSMR3GetU8(pSSM, &pThis->lcr);
- SSMR3GetU8(pSSM, &pThis->mcr);
- SSMR3GetU8(pSSM, &pThis->lsr);
- SSMR3GetU8(pSSM, &pThis->msr);
- SSMR3GetU8(pSSM, &pThis->scr);
- if (uVersion > SERIAL_SAVED_STATE_VERSION_16450)
- SSMR3GetU8(pSSM, &pThis->fcr);
- SSMR3GetS32(pSSM, &pThis->thr_ipending);
- SSMR3GetS32(pSSM, &iIrq);
- SSMR3GetS32(pSSM, &pThis->last_break_enable);
- SSMR3GetU32(pSSM, &IOBase);
- SSMR3GetBool(pSSM, &pThis->msr_changed);
-
- if (uVersion > SERIAL_SAVED_STATE_VERSION_MISSING_BITS)
+ else
{
- SSMR3GetU8(pSSM, &pThis->thr);
- SSMR3GetU8(pSSM, &pThis->tsr);
- SSMR3GetU8(pSSM, &pThis->iir);
- SSMR3GetS32(pSSM, &pThis->timeout_ipending);
- TMR3TimerLoad(pThis->fifo_timeout_timer, pSSM);
- TMR3TimerLoad(pThis->transmit_timerR3, pSSM);
- SSMR3GetU8(pSSM, &pThis->recv_fifo.itl);
- SSMR3GetU8(pSSM, &pThis->xmit_fifo.itl);
+ if (uVersion > UART_SAVED_STATE_VERSION_16450)
+ enmType = UARTTYPE_16550A;
+ else
+ enmType = UARTTYPE_16450;
+ rc = uartR3LoadExec(&pThis->UartCore, pSSM, uVersion, uPass, &uIrq, &PortBase);
}
-
- /* the marker. */
- uint32_t u32;
- int rc = SSMR3GetU32(pSSM, &u32);
- if (RT_FAILURE(rc))
- return rc;
- AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
-
- if ( (pThis->lsr & UART_LSR_DR)
- || pThis->fRecvWaiting)
+ if (RT_SUCCESS(rc))
{
- pThis->fRecvWaiting = false;
- rc = RTSemEventSignal(pThis->ReceiveSem);
- AssertRC(rc);
+ /* The marker. */
+ uint32_t u32;
+ rc = SSMR3GetU32(pSSM, &u32);
+ if (RT_FAILURE(rc))
+ return rc;
+ AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
}
-
- /* this isn't strictly necessary but cannot hurt... */
- pThis->pDevInsR3 = pDevIns;
- pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
- pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
}
/*
* Check the config.
*/
- if ( pThis->irq != iIrq
- || pThis->base != IOBase)
+ if ( pThis->uIrq != uIrq
+ || pThis->PortBase != PortBase
+ || pThis->UartCore.enmType != enmType)
return SSMR3SetCfgError(pSSM, RT_SRC_POS,
- N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
- iIrq, IOBase, pThis->irq, pThis->base);
+ N_("Config mismatch - saved IRQ=%#x PortBase=%#x Type=%d; configured IRQ=%#x PortBase=%#x Type=%d"),
+ uIrq, PortBase, enmType, pThis->uIrq, pThis->PortBase, pThis->UartCore.enmType);
return VINF_SUCCESS;
}
-#ifdef VBOX_SERIAL_PCI
-/* -=-=-=-=-=-=-=-=- PCI Device Callback(s) -=-=-=-=-=-=-=-=- */
-
/**
- * @callback_method_impl{FNPCIIOREGIONMAP}
+ * @callback_method_impl{FNSSMDEVLOADDONE}
*/
-static DECLCALLBACK(int) serialIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
- RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) serialR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
- PDEVSERIAL pThis = RT_FROM_MEMBER(pPciDev, DEVSERIAL, PciDev);
- int rc = VINF_SUCCESS;
-
- Assert(enmType == PCI_ADDRESS_SPACE_IO);
- Assert(iRegion == 0);
- Assert(cb == 8);
- AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
-
- pThis->base = (RTIOPORT)GCPhysAddress;
- LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
-
- /*
- * Register our port IO handlers.
- */
- rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
- serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
- AssertRC(rc);
- return rc;
-}
-
-#endif /* VBOX_SERIAL_PCI */
-
-
-/* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#1 -=-=-=-=-=-=-=-=- */
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PDEVSERIAL pThis = RT_FROM_MEMBER(pInterface, DEVSERIAL, IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
- return NULL;
+ PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
+ return uartR3LoadDone(&pThis->UartCore, pSSM);
}
@@ -1095,50 +255,20 @@ static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const cha
/**
* @interface_method_impl{PDMDEVREG,pfnRelocate}
*/
-static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
+static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
{
- RT_NOREF(offDelta);
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
- pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
+ uartR3Relocate(&pThis->UartCore, offDelta);
}
/**
* @interface_method_impl{PDMDEVREG,pfnReset}
*/
-static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
+static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
{
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
-
- pThis->rbr = 0;
- pThis->ier = 0;
- pThis->iir = UART_IIR_NO_INT;
- pThis->lcr = 3; /* 8 data bits, no parity, 1 stop bit */
- pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;
- pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
- /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
- pThis->divider = 0x0C;
- pThis->mcr = UART_MCR_OUT2;
- pThis->scr = 0;
- pThis->tsr_retry = 0;
- uint64_t tf = TMTimerGetFreq(CTX_SUFF(pThis->transmit_timer));
- pThis->char_transmit_time = (tf / 9600) * 10;
- serial_tsr_retry_update_parameters(pThis, tf);
-
- /* Update parameters of the underlying driver to stay in sync. */
- serial_update_parameters(pThis);
-
- fifo_clear(pThis, RECV_FIFO);
- fifo_clear(pThis, XMIT_FIFO);
-
- pThis->thr_ipending = 0;
- pThis->last_break_enable = 0;
-# ifdef VBOX_SERIAL_PCI
- PDMDevHlpPCISetIrqNoWait(pThis->CTX_SUFF(pDevIns), 0, 0);
-# else /* !VBOX_SERIAL_PCI */
- PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->irq, 0);
-# endif /* !VBOX_SERIAL_PCI */
+ uartR3Reset(&pThis->UartCore);
}
@@ -1147,30 +277,9 @@ static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
*/
static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
{
- RT_NOREF(iLUN, fFlags);
+ RT_NOREF(fFlags);
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
-
- int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
- if (RT_SUCCESS(rc))
- {
- pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
- if (!pThis->pDrvChar)
- {
- AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", pDevIns->iInstance));
- return VERR_PDM_MISSING_INTERFACE;
- }
- }
- else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- {
- pThis->pDrvBase = NULL;
- pThis->pDrvChar = NULL;
- rc = VINF_SUCCESS;
- LogRel(("Serial%d: no unit\n", pDevIns->iInstance));
- }
- else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
- LogRel(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", pDevIns->iInstance, rc));
-
- return rc;
+ return uartR3Attach(&pThis->UartCore, iLUN);
}
@@ -1181,25 +290,19 @@ static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint
{
RT_NOREF(iLUN, fFlags);
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
-
- /* Zero out important members. */
- pThis->pDrvBase = NULL;
- pThis->pDrvChar = NULL;
+ uartR3Detach(&pThis->UartCore);
}
/**
* @interface_method_impl{PDMDEVREG,pfnDestruct}
*/
-static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
+static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
{
PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
- RTSemEventDestroy(pThis->ReceiveSem);
- pThis->ReceiveSem = NIL_RTSEMEVENT;
-
- PDMR3CritSectDelete(&pThis->CritSect);
+ uartR3Destruct(&pThis->UartCore);
return VINF_SUCCESS;
}
@@ -1207,12 +310,10 @@ static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
-static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
+static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- int rc;
- uint16_t io_base;
- uint8_t irq_lvl;
+ PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
+ int rc = VINF_SUCCESS;
Assert(iInstance < 4);
PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
@@ -1224,31 +325,6 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->pDevInsR3 = pDevIns;
pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
- pThis->ReceiveSem = NIL_RTSEMEVENT;
-
- /* IBase */
- pThis->IBase.pfnQueryInterface = serialQueryInterface;
-
- /* ICharPort */
- pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
- pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
- pThis->ICharPort.pfnNotifyBufferFull = serialNotifyBufferFull;
- pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
-
-#ifdef VBOX_SERIAL_PCI
- /* the PCI device */
- pThis->PciDev.abConfig[0x00] = 0xee; /* Vendor: ??? */
- pThis->PciDev.abConfig[0x01] = 0x80;
- pThis->PciDev.abConfig[0x02] = 0x01; /* Device: ??? */
- pThis->PciDev.abConfig[0x03] = 0x01;
- pThis->PciDev.abConfig[0x04] = PCI_COMMAND_IOACCESS;
- pThis->PciDev.abConfig[0x09] = 0x01; /* Programming interface: 16450 */
- pThis->PciDev.abConfig[0x0a] = 0x00; /* Subclass: Serial controller */
- pThis->PciDev.abConfig[0x0b] = 0x07; /* Class: Communication controller */
- pThis->PciDev.abConfig[0x0e] = 0x00; /* Header type: standard */
- pThis->PciDev.abConfig[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
- pThis->PciDev.abConfig[0x3d] = 1; /* interrupt pin 0 */
-#endif /* VBOX_SERIAL_PCI */
/*
* Validate and read the configuration.
@@ -1258,14 +334,14 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
"GCEnabled\0"
"R0Enabled\0"
"YieldOnLSRRead\0"
- "Enable16550A\0"
+ "UartType\0"
))
{
AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
}
- rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
+ rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"GCEnabled\" value"));
@@ -1275,19 +351,21 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"R0Enabled\" value"));
- rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
+ bool fYieldOnLSRRead = false;
+ rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
- rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
+ uint8_t uIrq = 0;
+ rc = CFGMR3QueryU8(pCfg, "IRQ", &uIrq);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
/* Provide sensible defaults. */
if (iInstance == 0)
- irq_lvl = 4;
+ uIrq = 4;
else if (iInstance == 1)
- irq_lvl = 3;
+ uIrq = 3;
else
AssertReleaseFailed(); /* irq_lvl is undefined. */
}
@@ -1295,144 +373,100 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"IRQ\" value"));
- rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
+ uint16_t uIoBase = 0;
+ rc = CFGMR3QueryU16(pCfg, "IOBase", &uIoBase);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
if (iInstance == 0)
- io_base = 0x3f8;
+ uIoBase = 0x3f8;
else if (iInstance == 1)
- io_base = 0x2f8;
+ uIoBase = 0x2f8;
else
- AssertReleaseFailed(); /* io_base is undefined */
+ AssertReleaseFailed(); /* uIoBase is undefined */
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"IOBase\" value"));
- Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
-
- rc = CFGMR3QueryBoolDef(pCfg, "Enable16550A", &pThis->f16550AEnabled, true);
+ char *pszUartType;
+ rc = CFGMR3QueryStringAllocDef(pCfg, "UartType", &pszUartType, "16550A");
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to get the \"Enable16550A\" value"));
+ N_("Configuration error: failed to read \"UartType\" as string"));
- pThis->irq = irq_lvl;
-#ifdef VBOX_SERIAL_PCI
- pThis->base = -1;
-#else
- pThis->base = io_base;
-#endif
+ UARTTYPE enmUartType = serialR3GetUartTypeFromString(pszUartType);
- LogRel(("Serial#%d: emulating %s\n", pDevIns->iInstance, pThis->f16550AEnabled ? "16550A" : "16450"));
+ if (enmUartType != UARTTYPE_INVALID)
+ LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
+ pDevIns->iInstance, pszUartType, uIoBase, uIrq));
- /*
- * Initialize critical section and the semaphore. Change the default
- * critical section to ours so that TM and IOM will enter it before
- * calling us.
- *
- * Note! This must of be done BEFORE creating timers, registering I/O ports
- * and other things which might pick up the default CS or end up
- * calling back into the device.
- */
- rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%u", iInstance);
- AssertRCReturn(rc, rc);
+ MMR3HeapFree(pszUartType);
- rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
- AssertRCReturn(rc, rc);
+ if (enmUartType == UARTTYPE_INVALID)
+ return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
+ N_("Configuration error: \"UartType\" contains invalid type"));
- rc = RTSemEventCreate(&pThis->ReceiveSem);
- AssertRCReturn(rc, rc);
+ pThis->uIrq = uIrq;
+ pThis->PortBase = uIoBase;
/*
- * Create the timers.
- */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis,
- TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Serial Fifo Timer",
- &pThis->fifo_timeout_timer);
- AssertRCReturn(rc, rc);
-
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis,
- TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "Serial Transmit Timer",
- &pThis->transmit_timerR3);
- AssertRCReturn(rc, rc);
- pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
- pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
-
-#ifdef VBOX_SERIAL_PCI
- /*
- * Register the PCI Device and region.
+ * Init locks, using explicit locking where necessary.
*/
- rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
- if (RT_FAILURE(rc))
- return rc;
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
+ rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
if (RT_FAILURE(rc))
return rc;
-#else /* !VBOX_SERIAL_PCI */
/*
* Register the I/O ports.
*/
- pThis->base = io_base;
- rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
- serialIOPortWrite, serialIOPortRead,
+ rc = PDMDevHlpIOPortRegister(pDevIns, uIoBase, 8, 0,
+ serialIoPortWrite, serialIoPortRead,
NULL, NULL, "SERIAL");
if (RT_FAILURE(rc))
return rc;
- if (pThis->fGCEnabled)
+ PVM pVM = PDMDevHlpGetVM(pDevIns);
+ RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR;
+ RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR;
+
+ if (pThis->fRCEnabled)
{
- rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
- "serialIOPortRead", NULL, NULL, "Serial");
+ rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
+ "serialIoPortRead", NULL, NULL, "SERIAL");
+ if ( RT_SUCCESS(rc)
+ && VM_IS_RAW_MODE_ENABLED(pVM))
+ rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->szRCMod, "serialIrqReq", &pfnSerialIrqReqRC);
+
if (RT_FAILURE(rc))
return rc;
}
if (pThis->fR0Enabled)
{
- rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
- "serialIOPortRead", NULL, NULL, "Serial");
+ rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
+ "serialIoPortRead", NULL, NULL, "SERIAL");
+ if (RT_SUCCESS(rc))
+ rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "serialIrqReq", &pfnSerialIrqReqR0);
+
if (RT_FAILURE(rc))
return rc;
}
-#endif /* !VBOX_SERIAL_PCI */
/*
* Saved state.
*/
- rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
- serialLiveExec, serialSaveExec, serialLoadExec);
+ rc = PDMDevHlpSSMRegisterEx(pDevIns, UART_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
+ NULL, serialR3LiveExec, NULL,
+ NULL, serialR3SaveExec, NULL,
+ NULL, serialR3LoadExec, serialR3LoadDone);
if (RT_FAILURE(rc))
return rc;
- /*
- * Attach the char driver and get the interfaces.
- */
- rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
- if (RT_SUCCESS(rc))
- {
- pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
- if (!pThis->pDrvChar)
- {
- AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
- return VERR_PDM_MISSING_INTERFACE;
- }
- /** @todo provide read notification interface!!!! */
- }
- else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- {
- pThis->pDrvBase = NULL;
- pThis->pDrvChar = NULL;
- LogRel(("Serial%d: no unit\n", iInstance));
- }
- else
- {
- AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
- /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
- return rc;
- }
+ /* Init the UART core structure. */
+ rc = uartR3Init(&pThis->UartCore, pDevIns, enmUartType, 0,
+ fYieldOnLSRRead ? UART_CORE_YIELD_ON_LSR_READ : 0, serialIrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC);
- serialReset(pDevIns);
+ serialR3Reset(pDevIns);
return VINF_SUCCESS;
}
@@ -1461,17 +495,17 @@ const PDMDEVREG g_DeviceSerialPort =
/* cbInstance */
sizeof(DEVSERIAL),
/* pfnConstruct */
- serialConstruct,
+ serialR3Construct,
/* pfnDestruct */
- serialDestruct,
+ serialR3Destruct,
/* pfnRelocate */
- serialRelocate,
+ serialR3Relocate,
/* pfnMemSetup */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
- serialReset,
+ serialR3Reset,
/* pfnSuspend */
NULL,
/* pfnResume */
diff --git a/src/VBox/Devices/Serial/DevSerialNew.cpp b/src/VBox/Devices/Serial/DevSerialNew.cpp
deleted file mode 100644
index b8c90029088..00000000000
--- a/src/VBox/Devices/Serial/DevSerialNew.cpp
+++ /dev/null
@@ -1,530 +0,0 @@
-/* $Id$ */
-/** @file
- * DevSerial - 16550A UART emulation.
- *
- * The documentation for this device was taken from the PC16550D spec from TI.
- */
-
-/*
- * Copyright (C) 2018 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DEV_SERIAL
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdmserialifs.h>
-#include <VBox/vmm/vm.h>
-#include <iprt/assert.h>
-#include <iprt/uuid.h>
-#include <iprt/string.h>
-#include <iprt/semaphore.h>
-#include <iprt/critsect.h>
-
-#include "VBoxDD.h"
-#include "UartCore.h"
-
-
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-
-/**
- * Serial device.
- */
-typedef struct DEVSERIAL
-{
- /** Pointer to the device instance - R3 Ptr. */
- PPDMDEVINSR3 pDevInsR3;
- /** Pointer to the device instance - R0 Ptr. */
- PPDMDEVINSR0 pDevInsR0;
- /** Pointer to the device instance - RC Ptr. */
- PPDMDEVINSRC pDevInsRC;
- /** Alignment. */
- RTRCPTR Alignment0;
- /** Flag whether the R0 portion of this device is enabled. */
- bool fR0Enabled;
- /** Flag whether the RC portion of this device is enabled. */
- bool fRCEnabled;
- /** Alignment. */
- bool afAlignment1[2];
- /** The IRQ value. */
- uint8_t uIrq;
- /** The base I/O port the device is registered at. */
- RTIOPORT PortBase;
-
- /** The UART core. */
- UARTCORE UartCore;
-} DEVSERIAL;
-/** Pointer to the serial device state. */
-typedef DEVSERIAL *PDEVSERIAL;
-
-#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-
-
-/*********************************************************************************************************************************
-* Global Variables *
-*********************************************************************************************************************************/
-
-
-/*********************************************************************************************************************************
-* Internal Functions *
-*********************************************************************************************************************************/
-
-
-PDMBOTHCBDECL(void) serialIrqReq(PPDMDEVINS pDevIns, PUARTCORE pUart, unsigned iLUN, int iLvl)
-{
- RT_NOREF(pUart, iLUN);
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
-}
-
-
-/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
-
-/**
- * @callback_method_impl{FNIOMIOPORTOUT}
- */
-PDMBOTHCBDECL(int) serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- RT_NOREF_PV(pvUser);
-
- return uartRegWrite(&pThis->UartCore, uPort - pThis->PortBase, u32, cb);
-}
-
-
-/**
- * @callback_method_impl{FNIOMIOPORTIN}
- */
-PDMBOTHCBDECL(int) serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- RT_NOREF_PV(pvUser);
-
- return uartRegRead(&pThis->UartCore, uPort - pThis->PortBase, pu32, cb);
-}
-
-
-#ifdef IN_RING3
-
-
-/**
- * Returns the matching UART type from the given string.
- *
- * @returns UART type based on the given string or UARTTYPE_INVALID if an invalid type was passed.
- * @param pszUartType The UART type.
- */
-static UARTTYPE serialR3GetUartTypeFromString(const char *pszUartType)
-{
- if (!RTStrCmp(pszUartType, "16450"))
- return UARTTYPE_16450;
- else if (!RTStrCmp(pszUartType, "16550A"))
- return UARTTYPE_16550A;
- else if (!RTStrCmp(pszUartType, "16750"))
- return UARTTYPE_16750;
-
- AssertLogRelMsgFailedReturn(("Unknown UART type \"%s\" specified", pszUartType),
- UARTTYPE_INVALID);
-}
-
-
-/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
-
-/**
- * @callback_method_impl{FNSSMDEVLIVEEXEC}
- */
-static DECLCALLBACK(int) serialR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
-{
- RT_NOREF(uPass);
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- SSMR3PutU8(pSSM, pThis->uIrq);
- SSMR3PutIOPort(pSSM, pThis->PortBase);
- SSMR3PutU32(pSSM, pThis->UartCore.enmType);
-
- return VINF_SSM_DONT_CALL_AGAIN;
-}
-
-
-/**
- * @callback_method_impl{FNSSMDEVSAVEEXEC}
- */
-static DECLCALLBACK(int) serialR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
-
- SSMR3PutU8( pSSM, pThis->uIrq);
- SSMR3PutIOPort(pSSM, pThis->PortBase);
- SSMR3PutU32( pSSM, pThis->UartCore.enmType);
-
- uartR3SaveExec(&pThis->UartCore, pSSM);
- return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
-}
-
-
-/**
- * @callback_method_impl{FNSSMDEVLOADEXEC}
- */
-static DECLCALLBACK(int) serialR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- uint8_t uIrq;
- RTIOPORT PortBase;
- UARTTYPE enmType;
-
- AssertMsgReturn(uVersion >= UART_SAVED_STATE_VERSION_16450, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
-
- if (uPass != SSM_PASS_FINAL)
- {
- SSMR3GetU8(pSSM, &uIrq);
- SSMR3GetIOPort(pSSM, &PortBase);
- int rc = SSMR3GetU32(pSSM, (uint32_t *)&enmType);
- AssertRCReturn(rc, rc);
- }
- else
- {
- int rc = VINF_SUCCESS;
-
- if (uVersion > UART_SAVED_STATE_VERSION_LEGACY_CODE)
- {
- SSMR3GetU8( pSSM, &uIrq);
- SSMR3GetIOPort(pSSM, &PortBase);
- SSMR3GetU32( pSSM, (uint32_t *)&enmType);
- rc = uartR3LoadExec(&pThis->UartCore, pSSM, uVersion, uPass, NULL, NULL);
- }
- else
- {
- if (uVersion > UART_SAVED_STATE_VERSION_16450)
- enmType = UARTTYPE_16550A;
- else
- enmType = UARTTYPE_16450;
- rc = uartR3LoadExec(&pThis->UartCore, pSSM, uVersion, uPass, &uIrq, &PortBase);
- }
- if (RT_SUCCESS(rc))
- {
- /* The marker. */
- uint32_t u32;
- rc = SSMR3GetU32(pSSM, &u32);
- if (RT_FAILURE(rc))
- return rc;
- AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
- }
- }
-
- /*
- * Check the config.
- */
- if ( pThis->uIrq != uIrq
- || pThis->PortBase != PortBase
- || pThis->UartCore.enmType != enmType)
- return SSMR3SetCfgError(pSSM, RT_SRC_POS,
- N_("Config mismatch - saved IRQ=%#x PortBase=%#x Type=%d; configured IRQ=%#x PortBase=%#x Type=%d"),
- uIrq, PortBase, enmType, pThis->uIrq, pThis->PortBase, pThis->UartCore.enmType);
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{FNSSMDEVLOADDONE}
- */
-static DECLCALLBACK(int) serialR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- return uartR3LoadDone(&pThis->UartCore, pSSM);
-}
-
-
-/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnRelocate}
- */
-static DECLCALLBACK(void) serialR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- uartR3Relocate(&pThis->UartCore, offDelta);
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnReset}
- */
-static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- uartR3Reset(&pThis->UartCore);
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnAttach}
- */
-static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- return uartR3Attach(&pThis->UartCore, iLUN);
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnDetach}
- */
-static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
-{
- RT_NOREF(iLUN, fFlags);
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- uartR3Detach(&pThis->UartCore);
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnDestruct}
- */
-static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
-
- uartR3Destruct(&pThis->UartCore);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnConstruct}
- */
-static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
-{
- PDEVSERIAL pThis = PDMINS_2_DATA(pDevIns, PDEVSERIAL);
- int rc = VINF_SUCCESS;
-
- Assert(iInstance < 4);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
-
- /*
- * Initialize the instance data.
- * (Do this early or the destructor might choke on something!)
- */
- pThis->pDevInsR3 = pDevIns;
- pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
- pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-
- /*
- * Validate and read the configuration.
- */
- if (!CFGMR3AreValuesValid(pCfg, "IRQ\0"
- "IOBase\0"
- "GCEnabled\0"
- "R0Enabled\0"
- "YieldOnLSRRead\0"
- "UartType\0"
- ))
- {
- AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
- return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
- }
-
- rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to get the \"GCEnabled\" value"));
-
- rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to get the \"R0Enabled\" value"));
-
- bool fYieldOnLSRRead = false;
- rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
-
- uint8_t uIrq = 0;
- rc = CFGMR3QueryU8(pCfg, "IRQ", &uIrq);
- if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- {
- /* Provide sensible defaults. */
- if (iInstance == 0)
- uIrq = 4;
- else if (iInstance == 1)
- uIrq = 3;
- else
- AssertReleaseFailed(); /* irq_lvl is undefined. */
- }
- else if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to get the \"IRQ\" value"));
-
- uint16_t uIoBase = 0;
- rc = CFGMR3QueryU16(pCfg, "IOBase", &uIoBase);
- if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- {
- if (iInstance == 0)
- uIoBase = 0x3f8;
- else if (iInstance == 1)
- uIoBase = 0x2f8;
- else
- AssertReleaseFailed(); /* uIoBase is undefined */
- }
- else if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to get the \"IOBase\" value"));
-
- char *pszUartType;
- rc = CFGMR3QueryStringAllocDef(pCfg, "UartType", &pszUartType, "16550A");
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: failed to read \"UartType\" as string"));
-
- UARTTYPE enmUartType = serialR3GetUartTypeFromString(pszUartType);
-
- if (enmUartType != UARTTYPE_INVALID)
- LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n",
- pDevIns->iInstance, pszUartType, uIoBase, uIrq));
-
- MMR3HeapFree(pszUartType);
-
- if (enmUartType == UARTTYPE_INVALID)
- return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
- N_("Configuration error: \"UartType\" contains invalid type"));
-
- pThis->uIrq = uIrq;
- pThis->PortBase = uIoBase;
-
- /*
- * Init locks, using explicit locking where necessary.
- */
- rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Register the I/O ports.
- */
- rc = PDMDevHlpIOPortRegister(pDevIns, uIoBase, 8, 0,
- serialIoPortWrite, serialIoPortRead,
- NULL, NULL, "SERIAL");
- if (RT_FAILURE(rc))
- return rc;
-
- PVM pVM = PDMDevHlpGetVM(pDevIns);
- RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR;
- RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR;
-
- if (pThis->fRCEnabled)
- {
- rc = PDMDevHlpIOPortRegisterRC(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
- "serialIoPortRead", NULL, NULL, "SERIAL");
- if ( RT_SUCCESS(rc)
- && VM_IS_RAW_MODE_ENABLED(pVM))
- rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->szRCMod, "serialIrqReq", &pfnSerialIrqReqRC);
-
- if (RT_FAILURE(rc))
- return rc;
- }
-
- if (pThis->fR0Enabled)
- {
- rc = PDMDevHlpIOPortRegisterR0(pDevIns, uIoBase, 8, 0, "serialIoPortWrite",
- "serialIoPortRead", NULL, NULL, "SERIAL");
- if (RT_SUCCESS(rc))
- rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "serialIrqReq", &pfnSerialIrqReqR0);
-
- if (RT_FAILURE(rc))
- return rc;
- }
-
- /*
- * Saved state.
- */
- rc = PDMDevHlpSSMRegisterEx(pDevIns, UART_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
- NULL, serialR3LiveExec, NULL,
- NULL, serialR3SaveExec, NULL,
- NULL, serialR3LoadExec, serialR3LoadDone);
- if (RT_FAILURE(rc))
- return rc;
-
- /* Init the UART core structure. */
- rc = uartR3Init(&pThis->UartCore, pDevIns, enmUartType, 0,
- fYieldOnLSRRead ? UART_CORE_YIELD_ON_LSR_READ : 0, serialIrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC);
-
- serialR3Reset(pDevIns);
- return VINF_SUCCESS;
-}
-
-
-/**
- * The device registration structure.
- */
-const PDMDEVREG g_DeviceSerialPort =
-{
- /* u32Version */
- PDM_DEVREG_VERSION,
- /* szName */
- "serial",
- /* szRCMod */
- "VBoxDDRC.rc",
- /* szR0Mod */
- "VBoxDDR0.r0",
- /* pszDescription */
- "Serial Communication Port",
- /* fFlags */
- PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
- /* fClass */
- PDM_DEVREG_CLASS_SERIAL,
- /* cMaxInstances */
- UINT32_MAX,
- /* cbInstance */
- sizeof(DEVSERIAL),
- /* pfnConstruct */
- serialR3Construct,
- /* pfnDestruct */
- serialR3Destruct,
- /* pfnRelocate */
- serialR3Relocate,
- /* pfnMemSetup */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- serialR3Reset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- serialR3Attach,
- /* pfnDetach */
- serialR3Detach,
- /* pfnQueryInterface. */
- NULL,
- /* pfnInitComplete */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32VersionEnd */
- PDM_DEVREG_VERSION
-};
-#endif /* IN_RING3 */
-
-#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/Serial/DrvChar.cpp b/src/VBox/Devices/Serial/DrvChar.cpp
index 42ca8ce4830..3f3b314f0b0 100644
--- a/src/VBox/Devices/Serial/DrvChar.cpp
+++ b/src/VBox/Devices/Serial/DrvChar.cpp
@@ -1,16 +1,10 @@
/* $Id$ */
/** @file
- * Driver that adapts PDMISTREAM into PDMICHARCONNECTOR / PDMICHARPORT.
- *
- * Converts synchronous calls (PDMICHARCONNECTOR::pfnWrite, PDMISTREAM::pfnRead)
- * into asynchronous ones.
- *
- * Note that we don't use a send buffer here to be able to handle
- * dropping of bytes for xmit at device level.
+ * Driver that adapts PDMISTREAM into PDMISERIALCONNECTOR / PDMISERIALPORT.
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,6 +21,7 @@
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_CHAR
#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmserialifs.h>
#include <iprt/asm.h>
#include <iprt/assert.h>
#include <iprt/poll.h>
@@ -49,37 +44,31 @@
/**
* Char driver instance data.
*
- * @implements PDMICHARCONNECTOR
+ * @implements PDMISERIALCONNECTOR
*/
typedef struct DRVCHAR
{
/** Pointer to the driver instance structure. */
PPDMDRVINS pDrvIns;
/** Pointer to the char port interface of the driver/device above us. */
- PPDMICHARPORT pDrvCharPort;
+ PPDMISERIALPORT pDrvSerialPort;
/** Pointer to the stream interface of the driver below us. */
PPDMISTREAM pDrvStream;
- /** Our char interface. */
- PDMICHARCONNECTOR ICharConnector;
+ /** Our serial interface. */
+ PDMISERIALCONNECTOR ISerialConnector;
/** Flag to notify the receive thread it should terminate. */
volatile bool fShutdown;
+ /** Flag whether data is available from the device/driver above as notified by the driver. */
+ volatile bool fAvailWrExt;
+ /** Internal copy of the flag which gets reset when there is no data anymore. */
+ bool fAvailWrInt;
/** I/O thread. */
PPDMTHREAD pThrdIo;
- /** Thread to relay read data to the device above without
- * blocking send operations.
- * @todo: This has to go but needs changes in the interface
- * between device and driver.
- */
- PPDMTHREAD pThrdRead;
- /** Event semaphore for the read relay thread. */
- RTSEMEVENT hEvtSemRead;
- /** Critical section protection the send part. */
- RTCRITSECT CritSectSend;
- /** Internal send FIFO queue */
- uint8_t volatile u8SendByte;
- bool volatile fSending;
- uint8_t Alignment[2];
+ /** Small send buffer. */
+ uint8_t abTxBuf[16];
+ /** Amount of data in the buffer. */
+ size_t cbTxUsed;
/** Receive buffer. */
uint8_t abBuffer[256];
@@ -108,52 +97,99 @@ static DECLCALLBACK(void *) drvCharQueryInterface(PPDMIBASE pInterface, const ch
PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARCONNECTOR, &pThis->ICharConnector);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALCONNECTOR, &pThis->ISerialConnector);
return NULL;
}
-/* -=-=-=-=- ICharConnector -=-=-=-=- */
+/* -=-=-=-=- ISerialConnector -=-=-=-=- */
+
/**
- * @interface_method_impl{PDMICHARCONNECTOR,pfnWrite}
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnDataAvailWrNotify}
*/
-static DECLCALLBACK(int) drvCharWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
+static DECLCALLBACK(int) drvCharDataAvailWrNotify(PPDMISERIALCONNECTOR pInterface)
{
- PDRVCHAR pThis = RT_FROM_MEMBER(pInterface, DRVCHAR, ICharConnector);
- const char *pbBuffer = (const char *)pvBuf;
+ LogFlowFunc(("pInterface=%#p\n", pInterface));
+ PDRVCHAR pThis = RT_FROM_MEMBER(pInterface, DRVCHAR, ISerialConnector);
+
int rc = VINF_SUCCESS;
+ bool fAvailOld = ASMAtomicXchgBool(&pThis->fAvailWrExt, true);
+ if (!fAvailOld)
+ rc = pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
- LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
+ return rc;
+}
- RTCritSectEnter(&pThis->CritSectSend);
- for (uint32_t i = 0; i < cbWrite && RT_SUCCESS(rc); i++)
- {
- if (!ASMAtomicXchgBool(&pThis->fSending, true))
- {
- pThis->u8SendByte = pbBuffer[i];
- pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
- STAM_COUNTER_INC(&pThis->StatBytesWritten);
- }
- else
- rc = VERR_BUFFER_OVERFLOW;
- }
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnReadRdr}
+ */
+static DECLCALLBACK(int) drvCharReadRdr(PPDMISERIALCONNECTOR pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
+{
+ LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
+ PDRVCHAR pThis = RT_FROM_MEMBER(pInterface, DRVCHAR, ISerialConnector);
+ int rc = VINF_SUCCESS;
- RTCritSectLeave(&pThis->CritSectSend);
+ AssertReturn(pThis->cbRemaining, VERR_INVALID_STATE);
+ size_t cbToRead = RT_MIN(cbRead, pThis->cbRemaining);
+ memcpy(pvBuf, pThis->pbBuf, cbToRead);
+
+ pThis->pbBuf += cbToRead;
+ *pcbRead = cbToRead;
+ size_t cbOld = ASMAtomicSubZ(&pThis->cbRemaining, cbToRead);
+ if (!(cbOld - cbToRead)) /* Kick the I/O thread to fetch new data. */
+ rc = pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
+ STAM_COUNTER_ADD(&pThis->StatBytesRead, cbToRead);
+
+ LogFlowFunc(("-> %Rrc\n", rc));
return rc;
}
/**
- * @interface_method_impl{PDMICHARCONNECTOR,pfnSetParameters}
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgParams}
+ */
+static DECLCALLBACK(int) drvCharChgParams(PPDMISERIALCONNECTOR pInterface, uint32_t uBps,
+ PDMSERIALPARITY enmParity, unsigned cDataBits,
+ PDMSERIALSTOPBITS enmStopBits)
+{
+ /* Nothing to do here. */
+ RT_NOREF(pInterface, uBps, enmParity, cDataBits, enmStopBits);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{PDMISERIALCONNECTOR,pfnChgModemLines}
+ */
+static DECLCALLBACK(int) drvCharChgModemLines(PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)
+{
+ /* Nothing to do here. */
+ RT_NOREF(pInterface, fRts, fDtr);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{PDMISERIALCONNECTOR,pfnChgBrk}
*/
-static DECLCALLBACK(int) drvCharSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity,
- unsigned cDataBits, unsigned cStopBits)
+static DECLCALLBACK(int) drvCharChgBrk(PPDMISERIALCONNECTOR pInterface, bool fBrk)
{
- RT_NOREF(pInterface, Bps, chParity, cDataBits, cStopBits);
+ /* Nothing to do here. */
+ RT_NOREF(pInterface, fBrk);
+ return VINF_SUCCESS;
+}
- LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
+
+/**
+ * @callback_method_impl{PDMISERIALCONNECTOR,pfnQueryStsLines}
+ */
+static DECLCALLBACK(int) drvCharQueryStsLines(PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)
+{
+ /* Nothing to do here. */
+ *pfStsLines = 0;
+ RT_NOREF(pInterface);
return VINF_SUCCESS;
}
@@ -179,10 +215,14 @@ static DECLCALLBACK(int) drvCharIoLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
uint32_t fEvts = 0;
+ if (!pThis->fAvailWrInt)
+ pThis->fAvailWrInt = ASMAtomicXchgBool(&pThis->fAvailWrExt, false);
+
if ( !pThis->cbRemaining
&& pThis->pDrvStream->pfnRead)
fEvts |= RTPOLL_EVT_READ;
- if (pThis->fSending)
+ if ( pThis->fAvailWrInt
+ || pThis->cbTxUsed)
fEvts |= RTPOLL_EVT_WRITE;
uint32_t fEvtsRecv = 0;
@@ -191,32 +231,46 @@ static DECLCALLBACK(int) drvCharIoLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
if (fEvtsRecv & RTPOLL_EVT_WRITE)
{
- RTCritSectEnter(&pThis->CritSectSend);
- Assert(pThis->fSending);
-
- size_t cbProcessed = 1;
- uint8_t ch = pThis->u8SendByte;
- rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &ch, &cbProcessed);
- if (RT_SUCCESS(rc))
+ if (pThis->fAvailWrInt)
{
- ASMAtomicXchgBool(&pThis->fSending, false);
- Assert(cbProcessed == 1);
+ /* Stuff as much data into the TX buffer as we can. */
+ size_t cbToFetch = RT_ELEMENTS(pThis->abTxBuf) - pThis->cbTxUsed;
+ size_t cbFetched = 0;
+ rc = pThis->pDrvSerialPort->pfnReadWr(pThis->pDrvSerialPort, &pThis->abTxBuf[pThis->cbTxUsed], cbToFetch,
+ &cbFetched);
+ AssertRC(rc);
+
+ if (cbFetched > 0)
+ pThis->cbTxUsed += cbFetched;
+ else
+ {
+ /* There is no data available anymore. */
+ pThis->fAvailWrInt = false;
+ }
}
- else if (rc == VERR_TIMEOUT)
- {
- /* Normal case, just means that the stream didn't accept a new
- * character before the timeout elapsed. Just retry. */
- /* do not change the rc status here, otherwise the (rc == VERR_TIMEOUT) branch
- * in the wait above will never get executed */
- /* rc = VINF_SUCCESS; */
- }
- else
+ if (pThis->cbTxUsed)
{
- LogRel(("Write failed with %Rrc; skipping\n", rc));
- break;
+ size_t cbProcessed = pThis->cbTxUsed;
+ rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &pThis->abTxBuf[0], &cbProcessed);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->cbTxUsed -= cbProcessed;
+ if (pThis->cbTxUsed)
+ {
+ /* Move the data in the TX buffer to the front to fill the end again. */
+ memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed);
+ }
+ else
+ pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort);
+ STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbProcessed);
+ }
+ else if (rc != VERR_TIMEOUT)
+ {
+ LogRel(("Char#%d: Write failed with %Rrc; skipping\n", pDrvIns->iInstance, rc));
+ break;
+ }
}
- RTCritSectLeave(&pThis->CritSectSend);
}
if (fEvtsRecv & RTPOLL_EVT_READ)
@@ -231,9 +285,14 @@ static DECLCALLBACK(int) drvCharIoLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
LogFlow(("Read failed with %Rrc\n", rc));
break;
}
- pThis->pbBuf = &pThis->abBuffer[0];
- ASMAtomicWriteZ(&pThis->cbRemaining, cbRead);
- RTSemEventSignal(pThis->hEvtSemRead); /* Wakeup relay thread to continue. */
+
+ if (cbRead)
+ {
+ pThis->pbBuf = &pThis->abBuffer[0];
+ ASMAtomicWriteZ(&pThis->cbRemaining, cbRead);
+ /* Notify the upper device/driver. */
+ rc = pThis->pDrvSerialPort->pfnDataAvailRdrNotify(pThis->pDrvSerialPort, cbRead);
+ }
}
}
else if (rc != VERR_INTERRUPTED)
@@ -260,123 +319,21 @@ static DECLCALLBACK(int) drvCharIoLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThr
}
-static DECLCALLBACK(int) drvCharReadRelayLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- RT_NOREF(pDrvIns);
- PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser;
-
- if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
- return VINF_SUCCESS;
-
- int rc = VINF_SUCCESS;
- while (pThread->enmState == PDMTHREADSTATE_RUNNING)
- {
- size_t cbRem = ASMAtomicReadZ(&pThis->cbRemaining);
-
- /* Block as long as there is nothing to relay. */
- if (!pThis->cbRemaining)
- rc = RTSemEventWait(pThis->hEvtSemRead, RT_INDEFINITE_WAIT);
-
- if (pThread->enmState != PDMTHREADSTATE_RUNNING)
- break;
-
- cbRem = ASMAtomicReadZ(&pThis->cbRemaining);
- if (cbRem)
- {
- /* Send data to guest. */
- size_t cbProcessed = cbRem;
- rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pThis->pbBuf, &cbProcessed);
- if (RT_SUCCESS(rc))
- {
- Assert(cbProcessed);
- pThis->pbBuf += cbProcessed;
-
- /* Wake up the I/o thread so it can read new data to process. */
- cbRem = ASMAtomicSubZ(&pThis->cbRemaining, cbProcessed);
- if (cbRem == cbProcessed)
- pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
- STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
- }
- else if (rc == VERR_TIMEOUT)
- {
- /* Normal case, just means that the guest didn't accept a new
- * character before the timeout elapsed. Just retry. */
- rc = VINF_SUCCESS;
- }
- else
- {
- LogFlow(("NotifyRead failed with %Rrc\n", rc));
- break;
- }
- }
- }
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Unblock the read relay worker thread so it can respond to a state change.
- *
- * @returns VBox status code.
- * @param pDrvIns The char driver instance.
- * @param pThread The worker thread.
- */
-static DECLCALLBACK(int) drvCharReadRelayLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser;
-
- RT_NOREF(pDrvIns);
- return RTSemEventSignal(pThis->hEvtSemRead);
-}
-
-
-/**
- * @callback_method_impl{PDMICHARCONNECTOR,pfnSetModemLines}
- */
-static DECLCALLBACK(int) drvCharSetModemLines(PPDMICHARCONNECTOR pInterface, bool fRequestToSend, bool fDataTerminalReady)
-{
- /* Nothing to do here. */
- RT_NOREF(pInterface, fRequestToSend, fDataTerminalReady);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{PDMICHARCONNECTOR,pfnSetBreak}
- */
-static DECLCALLBACK(int) drvCharSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak)
-{
- /* Nothing to do here. */
- RT_NOREF(pInterface, fBreak);
- return VINF_SUCCESS;
-}
-
-
/* -=-=-=-=- driver interface -=-=-=-=- */
/**
- * Destruct a char driver instance.
- *
- * Most VM resources are freed by the VM. This callback is provided so that
- * any non-VM resources can be freed correctly.
- *
- * @param pDrvIns The driver instance data.
+ * @interface_method_impl{PDMDEVREG,pfnReset}
*/
-static DECLCALLBACK(void) drvCharDestruct(PPDMDRVINS pDrvIns)
+static DECLCALLBACK(void) drvCharReset(PPDMDRVINS pDrvIns)
{
- PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
- LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+ PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
- if (RTCritSectIsInitialized(&pThis->CritSectSend))
- RTCritSectDelete(&pThis->CritSectSend);
-
- if (pThis->hEvtSemRead != NIL_RTSEMEVENT)
- {
- RTSemEventDestroy(pThis->hEvtSemRead);
- pThis->hEvtSemRead = NIL_RTSEMEVENT;
- }
+ /* Reset TX and RX buffers. */
+ pThis->fAvailWrExt = false;
+ pThis->fAvailWrInt = false;
+ pThis->cbTxUsed = 0;
+ pThis->cbRemaining = 0;
}
@@ -395,61 +352,48 @@ static DECLCALLBACK(int) drvCharConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, ui
/*
* Init basic data members and interfaces.
*/
- pThis->pDrvIns = pDrvIns;
- pThis->pThrdIo = NIL_RTTHREAD;
- pThis->pThrdRead = NIL_RTTHREAD;
- pThis->hEvtSemRead = NIL_RTSEMEVENT;
+ pThis->pDrvIns = pDrvIns;
+ pThis->pThrdIo = NIL_RTTHREAD;
/* IBase. */
- pDrvIns->IBase.pfnQueryInterface = drvCharQueryInterface;
- /* ICharConnector. */
- pThis->ICharConnector.pfnWrite = drvCharWrite;
- pThis->ICharConnector.pfnSetParameters = drvCharSetParameters;
- pThis->ICharConnector.pfnSetModemLines = drvCharSetModemLines;
- pThis->ICharConnector.pfnSetBreak = drvCharSetBreak;
-
- int rc = RTCritSectInit(&pThis->CritSectSend);
- if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
- N_("Char#%d: Failed to create critical section"), pDrvIns->iInstance);
+ pDrvIns->IBase.pfnQueryInterface = drvCharQueryInterface;
+ /* ISerialConnector. */
+ pThis->ISerialConnector.pfnDataAvailWrNotify = drvCharDataAvailWrNotify;
+ pThis->ISerialConnector.pfnReadRdr = drvCharReadRdr;
+ pThis->ISerialConnector.pfnChgParams = drvCharChgParams;
+ pThis->ISerialConnector.pfnChgModemLines = drvCharChgModemLines;
+ pThis->ISerialConnector.pfnChgBrk = drvCharChgBrk;
+ pThis->ISerialConnector.pfnQueryStsLines = drvCharQueryStsLines;
/*
- * Get the ICharPort interface of the above driver/device.
+ * Get the ISerialPort interface of the above driver/device.
*/
- pThis->pDrvCharPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICHARPORT);
- if (!pThis->pDrvCharPort)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Char#%d has no char port interface above"), pDrvIns->iInstance);
+ pThis->pDrvSerialPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISERIALPORT);
+ if (!pThis->pDrvSerialPort)
+ return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS,
+ N_("Char#%d has no serial port interface above"), pDrvIns->iInstance);
/*
* Attach driver below and query its stream interface.
*/
PPDMIBASE pBase;
- rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
+ int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
if (RT_FAILURE(rc))
return rc; /* Don't call PDMDrvHlpVMSetError here as we assume that the driver already set an appropriate error */
pThis->pDrvStream = PDMIBASE_QUERY_INTERFACE(pBase, PDMISTREAM);
if (!pThis->pDrvStream)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("Char#%d has no stream interface below"), pDrvIns->iInstance);
-
- /* Don't start the receive relay thread if reading is not supported. */
- if (pThis->pDrvStream->pfnRead)
- {
- rc = PDMDrvHlpThreadCreate(pThis->pDrvIns, &pThis->pThrdRead, pThis, drvCharReadRelayLoop,
- drvCharReadRelayLoopWakeup, 0, RTTHREADTYPE_IO, "CharReadRel");
- if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create read relay thread"), pDrvIns->iInstance);
-
- rc = RTSemEventCreate(&pThis->hEvtSemRead);
- AssertRCReturn(rc, rc);
- }
+ return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
+ N_("Char#%d has no stream interface below"), pDrvIns->iInstance);
rc = PDMDrvHlpThreadCreate(pThis->pDrvIns, &pThis->pThrdIo, pThis, drvCharIoLoop,
drvCharIoLoopWakeup, 0, RTTHREADTYPE_IO, "CharIo");
if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create send thread"), pDrvIns->iInstance);
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create I/O thread"), pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/Char%d/Written", pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/Char%d/Read", pDrvIns->iInstance);
+ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
+ "Nr of bytes written", "/Devices/Char%d/Written", pDrvIns->iInstance);
+ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
+ "Nr of bytes read", "/Devices/Char%d/Read", pDrvIns->iInstance);
return VINF_SUCCESS;
}
@@ -481,7 +425,7 @@ const PDMDRVREG g_DrvChar =
/* pfnConstruct */
drvCharConstruct,
/* pfnDestruct */
- drvCharDestruct,
+ NULL,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
@@ -489,7 +433,7 @@ const PDMDRVREG g_DrvChar =
/* pfnPowerOn */
NULL,
/* pfnReset */
- NULL,
+ drvCharReset,
/* pfnSuspend */
NULL,
/* pfnResume */
diff --git a/src/VBox/Devices/Serial/DrvCharNew.cpp b/src/VBox/Devices/Serial/DrvCharNew.cpp
deleted file mode 100644
index 3f3b314f0b0..00000000000
--- a/src/VBox/Devices/Serial/DrvCharNew.cpp
+++ /dev/null
@@ -1,451 +0,0 @@
-/* $Id$ */
-/** @file
- * Driver that adapts PDMISTREAM into PDMISERIALCONNECTOR / PDMISERIALPORT.
- */
-
-/*
- * Copyright (C) 2006-2018 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_CHAR
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/vmm/pdmserialifs.h>
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/poll.h>
-#include <iprt/stream.h>
-#include <iprt/critsect.h>
-#include <iprt/semaphore.h>
-#include <iprt/uuid.h>
-
-#include "VBoxDD.h"
-
-
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-/**
- * Char driver instance data.
- *
- * @implements PDMISERIALCONNECTOR
- */
-typedef struct DRVCHAR
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to the char port interface of the driver/device above us. */
- PPDMISERIALPORT pDrvSerialPort;
- /** Pointer to the stream interface of the driver below us. */
- PPDMISTREAM pDrvStream;
- /** Our serial interface. */
- PDMISERIALCONNECTOR ISerialConnector;
- /** Flag to notify the receive thread it should terminate. */
- volatile bool fShutdown;
- /** Flag whether data is available from the device/driver above as notified by the driver. */
- volatile bool fAvailWrExt;
- /** Internal copy of the flag which gets reset when there is no data anymore. */
- bool fAvailWrInt;
- /** I/O thread. */
- PPDMTHREAD pThrdIo;
-
- /** Small send buffer. */
- uint8_t abTxBuf[16];
- /** Amount of data in the buffer. */
- size_t cbTxUsed;
-
- /** Receive buffer. */
- uint8_t abBuffer[256];
- /** Number of bytes remaining in the receive buffer. */
- volatile size_t cbRemaining;
- /** Current position into the read buffer. */
- uint8_t *pbBuf;
-
- /** Read/write statistics */
- STAMCOUNTER StatBytesRead;
- STAMCOUNTER StatBytesWritten;
-} DRVCHAR, *PDRVCHAR;
-AssertCompileMemberAlignment(DRVCHAR, StatBytesRead, 8);
-
-
-
-
-/* -=-=-=-=- IBase -=-=-=-=- */
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvCharQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALCONNECTOR, &pThis->ISerialConnector);
- return NULL;
-}
-
-
-/* -=-=-=-=- ISerialConnector -=-=-=-=- */
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnDataAvailWrNotify}
- */
-static DECLCALLBACK(int) drvCharDataAvailWrNotify(PPDMISERIALCONNECTOR pInterface)
-{
- LogFlowFunc(("pInterface=%#p\n", pInterface));
- PDRVCHAR pThis = RT_FROM_MEMBER(pInterface, DRVCHAR, ISerialConnector);
-
- int rc = VINF_SUCCESS;
- bool fAvailOld = ASMAtomicXchgBool(&pThis->fAvailWrExt, true);
- if (!fAvailOld)
- rc = pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnReadRdr}
- */
-static DECLCALLBACK(int) drvCharReadRdr(PPDMISERIALCONNECTOR pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
-{
- LogFlowFunc(("pInterface=%#p pvBuf=%#p cbRead=%zu pcbRead=%#p\n", pInterface, pvBuf, cbRead, pcbRead));
- PDRVCHAR pThis = RT_FROM_MEMBER(pInterface, DRVCHAR, ISerialConnector);
- int rc = VINF_SUCCESS;
-
- AssertReturn(pThis->cbRemaining, VERR_INVALID_STATE);
- size_t cbToRead = RT_MIN(cbRead, pThis->cbRemaining);
- memcpy(pvBuf, pThis->pbBuf, cbToRead);
-
- pThis->pbBuf += cbToRead;
- *pcbRead = cbToRead;
- size_t cbOld = ASMAtomicSubZ(&pThis->cbRemaining, cbToRead);
- if (!(cbOld - cbToRead)) /* Kick the I/O thread to fetch new data. */
- rc = pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
- STAM_COUNTER_ADD(&pThis->StatBytesRead, cbToRead);
-
- LogFlowFunc(("-> %Rrc\n", rc));
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgParams}
- */
-static DECLCALLBACK(int) drvCharChgParams(PPDMISERIALCONNECTOR pInterface, uint32_t uBps,
- PDMSERIALPARITY enmParity, unsigned cDataBits,
- PDMSERIALSTOPBITS enmStopBits)
-{
- /* Nothing to do here. */
- RT_NOREF(pInterface, uBps, enmParity, cDataBits, enmStopBits);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{PDMISERIALCONNECTOR,pfnChgModemLines}
- */
-static DECLCALLBACK(int) drvCharChgModemLines(PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)
-{
- /* Nothing to do here. */
- RT_NOREF(pInterface, fRts, fDtr);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{PDMISERIALCONNECTOR,pfnChgBrk}
- */
-static DECLCALLBACK(int) drvCharChgBrk(PPDMISERIALCONNECTOR pInterface, bool fBrk)
-{
- /* Nothing to do here. */
- RT_NOREF(pInterface, fBrk);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{PDMISERIALCONNECTOR,pfnQueryStsLines}
- */
-static DECLCALLBACK(int) drvCharQueryStsLines(PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)
-{
- /* Nothing to do here. */
- *pfStsLines = 0;
- RT_NOREF(pInterface);
- return VINF_SUCCESS;
-}
-
-
-/* -=-=-=-=- I/O thread -=-=-=-=- */
-
-/**
- * Send thread loop - pushes data down thru the driver chain.
- *
- * @returns VBox status code.
- * @param pDrvIns The char driver instance.
- * @param pThread The worker thread.
- */
-static DECLCALLBACK(int) drvCharIoLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- RT_NOREF(pDrvIns);
- PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser;
-
- if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
- return VINF_SUCCESS;
-
- while (pThread->enmState == PDMTHREADSTATE_RUNNING)
- {
- uint32_t fEvts = 0;
-
- if (!pThis->fAvailWrInt)
- pThis->fAvailWrInt = ASMAtomicXchgBool(&pThis->fAvailWrExt, false);
-
- if ( !pThis->cbRemaining
- && pThis->pDrvStream->pfnRead)
- fEvts |= RTPOLL_EVT_READ;
- if ( pThis->fAvailWrInt
- || pThis->cbTxUsed)
- fEvts |= RTPOLL_EVT_WRITE;
-
- uint32_t fEvtsRecv = 0;
- int rc = pThis->pDrvStream->pfnPoll(pThis->pDrvStream, fEvts, &fEvtsRecv, RT_INDEFINITE_WAIT);
- if (RT_SUCCESS(rc))
- {
- if (fEvtsRecv & RTPOLL_EVT_WRITE)
- {
- if (pThis->fAvailWrInt)
- {
- /* Stuff as much data into the TX buffer as we can. */
- size_t cbToFetch = RT_ELEMENTS(pThis->abTxBuf) - pThis->cbTxUsed;
- size_t cbFetched = 0;
- rc = pThis->pDrvSerialPort->pfnReadWr(pThis->pDrvSerialPort, &pThis->abTxBuf[pThis->cbTxUsed], cbToFetch,
- &cbFetched);
- AssertRC(rc);
-
- if (cbFetched > 0)
- pThis->cbTxUsed += cbFetched;
- else
- {
- /* There is no data available anymore. */
- pThis->fAvailWrInt = false;
- }
- }
-
- if (pThis->cbTxUsed)
- {
- size_t cbProcessed = pThis->cbTxUsed;
- rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &pThis->abTxBuf[0], &cbProcessed);
- if (RT_SUCCESS(rc))
- {
- pThis->cbTxUsed -= cbProcessed;
- if (pThis->cbTxUsed)
- {
- /* Move the data in the TX buffer to the front to fill the end again. */
- memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed);
- }
- else
- pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort);
- STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbProcessed);
- }
- else if (rc != VERR_TIMEOUT)
- {
- LogRel(("Char#%d: Write failed with %Rrc; skipping\n", pDrvIns->iInstance, rc));
- break;
- }
- }
- }
-
- if (fEvtsRecv & RTPOLL_EVT_READ)
- {
- AssertPtr(pThis->pDrvStream->pfnRead);
- Assert(!pThis->cbRemaining);
-
- size_t cbRead = sizeof(pThis->abBuffer);
- rc = pThis->pDrvStream->pfnRead(pThis->pDrvStream, &pThis->abBuffer[0], &cbRead);
- if (RT_FAILURE(rc))
- {
- LogFlow(("Read failed with %Rrc\n", rc));
- break;
- }
-
- if (cbRead)
- {
- pThis->pbBuf = &pThis->abBuffer[0];
- ASMAtomicWriteZ(&pThis->cbRemaining, cbRead);
- /* Notify the upper device/driver. */
- rc = pThis->pDrvSerialPort->pfnDataAvailRdrNotify(pThis->pDrvSerialPort, cbRead);
- }
- }
- }
- else if (rc != VERR_INTERRUPTED)
- LogRelMax(10, ("Char#%d: Polling failed with %Rrc\n", pDrvIns->iInstance, rc));
- }
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Unblock the send worker thread so it can respond to a state change.
- *
- * @returns VBox status code.
- * @param pDrvIns The char driver instance.
- * @param pThread The worker thread.
- */
-static DECLCALLBACK(int) drvCharIoLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser;
-
- RT_NOREF(pDrvIns);
- return pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream);
-}
-
-
-/* -=-=-=-=- driver interface -=-=-=-=- */
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnReset}
- */
-static DECLCALLBACK(void) drvCharReset(PPDMDRVINS pDrvIns)
-{
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
-
- /* Reset TX and RX buffers. */
- pThis->fAvailWrExt = false;
- pThis->fAvailWrInt = false;
- pThis->cbTxUsed = 0;
- pThis->cbRemaining = 0;
-}
-
-
-/**
- * Construct a char driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvCharConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(pCfg);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
- PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
- LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
-
- /*
- * Init basic data members and interfaces.
- */
- pThis->pDrvIns = pDrvIns;
- pThis->pThrdIo = NIL_RTTHREAD;
- /* IBase. */
- pDrvIns->IBase.pfnQueryInterface = drvCharQueryInterface;
- /* ISerialConnector. */
- pThis->ISerialConnector.pfnDataAvailWrNotify = drvCharDataAvailWrNotify;
- pThis->ISerialConnector.pfnReadRdr = drvCharReadRdr;
- pThis->ISerialConnector.pfnChgParams = drvCharChgParams;
- pThis->ISerialConnector.pfnChgModemLines = drvCharChgModemLines;
- pThis->ISerialConnector.pfnChgBrk = drvCharChgBrk;
- pThis->ISerialConnector.pfnQueryStsLines = drvCharQueryStsLines;
-
- /*
- * Get the ISerialPort interface of the above driver/device.
- */
- pThis->pDrvSerialPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISERIALPORT);
- if (!pThis->pDrvSerialPort)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS,
- N_("Char#%d has no serial port interface above"), pDrvIns->iInstance);
-
- /*
- * Attach driver below and query its stream interface.
- */
- PPDMIBASE pBase;
- int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
- if (RT_FAILURE(rc))
- return rc; /* Don't call PDMDrvHlpVMSetError here as we assume that the driver already set an appropriate error */
- pThis->pDrvStream = PDMIBASE_QUERY_INTERFACE(pBase, PDMISTREAM);
- if (!pThis->pDrvStream)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
- N_("Char#%d has no stream interface below"), pDrvIns->iInstance);
-
- rc = PDMDrvHlpThreadCreate(pThis->pDrvIns, &pThis->pThrdIo, pThis, drvCharIoLoop,
- drvCharIoLoopWakeup, 0, RTTHREADTYPE_IO, "CharIo");
- if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create I/O thread"), pDrvIns->iInstance);
-
-
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
- "Nr of bytes written", "/Devices/Char%d/Written", pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
- "Nr of bytes read", "/Devices/Char%d/Read", pDrvIns->iInstance);
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvChar =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "Char",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Generic char driver.",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_CHAR,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVCHAR),
- /* pfnConstruct */
- drvCharConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- drvCharReset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
diff --git a/src/VBox/Devices/Serial/DrvHostSerial.cpp b/src/VBox/Devices/Serial/DrvHostSerial.cpp
index ae16a3acd19..ea5c670066f 100644
--- a/src/VBox/Devices/Serial/DrvHostSerial.cpp
+++ b/src/VBox/Devices/Serial/DrvHostSerial.cpp
@@ -1,10 +1,10 @@
/* $Id$ */
/** @file
- * VBox stream I/O devices: Host serial driver
+ * VBox serial devices: Host serial driver
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -22,6 +22,7 @@
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
#include <VBox/vmm/pdm.h>
+#include <VBox/vmm/pdmserialifs.h>
#include <VBox/err.h>
#include <VBox/log.h>
@@ -32,42 +33,7 @@
#include <iprt/pipe.h>
#include <iprt/semaphore.h>
#include <iprt/uuid.h>
-
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
-# include <errno.h>
-# ifdef RT_OS_SOLARIS
-# include <sys/termios.h>
-# else
-# include <termios.h>
-# endif
-# include <sys/types.h>
-# include <fcntl.h>
-# include <string.h>
-# include <unistd.h>
-# ifdef RT_OS_DARWIN
-# include <sys/select.h>
-# else
-# include <sys/poll.h>
-# endif
-# include <sys/ioctl.h>
-# include <pthread.h>
-
-# ifdef RT_OS_LINUX
-/*
- * TIOCM_LOOP is not defined in the above header files for some reason but in asm/termios.h.
- * But inclusion of this file however leads to compilation errors because of redefinition of some
- * structs. That's why it is defined here until a better solution is found.
- */
-# ifndef TIOCM_LOOP
-# define TIOCM_LOOP 0x8000
-# endif
-/* For linux custom baudrate code we also need serial_struct */
-# include <linux/serial.h>
-# endif /* linux */
-
-#elif defined(RT_OS_WINDOWS)
-# include <iprt/win/windows.h>
-#endif
+#include <iprt/serialport.h>
#include "VBoxDD.h"
@@ -79,76 +45,128 @@
/**
* Char driver instance data.
*
- * @implements PDMICHARCONNECTOR
+ * @implements PDMISERIALCONNECTOR
*/
typedef struct DRVHOSTSERIAL
{
/** Pointer to the driver instance structure. */
PPDMDRVINS pDrvIns;
- /** Pointer to the char port interface of the driver/device above us. */
- PPDMICHARPORT pDrvCharPort;
- /** Our char interface. */
- PDMICHARCONNECTOR ICharConnector;
- /** Receive thread. */
- PPDMTHREAD pRecvThread;
- /** Send thread. */
- PPDMTHREAD pSendThread;
- /** Status lines monitor thread. */
- PPDMTHREAD pMonitorThread;
- /** Send event semaphore */
- RTSEMEVENT SendSem;
-
+ /** Pointer to the serial port interface of the driver/device above us. */
+ PPDMISERIALPORT pDrvSerialPort;
+ /** Our serial interface. */
+ PDMISERIALCONNECTOR ISerialConnector;
+ /** I/O thread. */
+ PPDMTHREAD pIoThrd;
+ /** The serial port handle. */
+ RTSERIALPORT hSerialPort;
/** the device path */
char *pszDevicePath;
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- /** the device handle */
- RTFILE hDeviceFile;
-# ifdef RT_OS_DARWIN
- /** The device handle used for reading.
- * Used to prevent the read select from blocking the writes. */
- RTFILE hDeviceFileR;
-# endif
- /** The read end of the control pipe */
- RTPIPE hWakeupPipeR;
- /** The write end of the control pipe */
- RTPIPE hWakeupPipeW;
- /** The current line status.
- * Used by the polling version of drvHostSerialMonitorThread. */
- int fStatusLines;
-#elif defined(RT_OS_WINDOWS)
- /** the device handle */
- HANDLE hDeviceFile;
- /** The event semaphore for waking up the receive thread */
- HANDLE hHaltEventSem;
- /** The event semaphore for overlapped receiving */
- HANDLE hEventRecv;
- /** For overlapped receiving */
- OVERLAPPED overlappedRecv;
- /** The event semaphore for overlapped sending */
- HANDLE hEventSend;
- /** For overlapped sending */
- OVERLAPPED overlappedSend;
-#endif
-
- /** Internal send FIFO queue */
- uint8_t volatile u8SendByte;
- bool volatile fSending;
- uint8_t Alignment[2];
+ /** Flag whether data is available from the device/driver above as notified by the driver. */
+ volatile bool fAvailWrExt;
+ /** Internal copy of the flag which gets reset when there is no data anymore. */
+ bool fAvailWrInt;
+ /** Small send buffer. */
+ uint8_t abTxBuf[16];
+ /** Amount of data in the buffer. */
+ size_t cbTxUsed;
+
+ /** The read queue. */
+ uint8_t abReadBuf[256];
+ /** Current offset to write to next. */
+ volatile uint32_t offWrite;
+ /** Current offset into the read buffer. */
+ volatile uint32_t offRead;
+ /** Current amount of data in the buffer. */
+ volatile size_t cbReadBuf;
/** Read/write statistics */
STAMCOUNTER StatBytesRead;
STAMCOUNTER StatBytesWritten;
-#ifdef RT_OS_DARWIN
- /** The number of bytes we've dropped because the send queue
- * was full. */
- STAMCOUNTER StatSendOverflows;
-#endif
} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
-/** Converts a pointer to DRVCHAR::ICharConnector to a PDRVHOSTSERIAL. */
-#define PDMICHAR_2_DRVHOSTSERIAL(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector)
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+
+
+/**
+ * Returns number of bytes free in the read buffer and pointer to the start of the free space
+ * in the read buffer.
+ *
+ * @returns Number of bytes free in the buffer.
+ * @param pThis The host serial driver instance.
+ * @param ppv Where to return the pointer if there is still free space.
+ */
+DECLINLINE(size_t) drvHostSerialReadBufGetWrite(PDRVHOSTSERIAL pThis, void **ppv)
+{
+ if (ppv)
+ *ppv = &pThis->abReadBuf[pThis->offWrite];
+
+ size_t cbFree = sizeof(pThis->abReadBuf) - ASMAtomicReadZ(&pThis->cbReadBuf);
+ if (cbFree)
+ cbFree = RT_MIN(cbFree, sizeof(pThis->abReadBuf) - pThis->offWrite);
+
+ return cbFree;
+}
+
+
+/**
+ * Returns number of bytes used in the read buffer and pointer to the next byte to read.
+ *
+ * @returns Number of bytes free in the buffer.
+ * @param pThis The host serial driver instance.
+ * @param ppv Where to return the pointer to the next data to read.
+ */
+DECLINLINE(size_t) drvHostSerialReadBufGetRead(PDRVHOSTSERIAL pThis, void **ppv)
+{
+ if (ppv)
+ *ppv = &pThis->abReadBuf[pThis->offRead];
+
+ size_t cbUsed = ASMAtomicReadZ(&pThis->cbReadBuf);
+ if (cbUsed)
+ cbUsed = RT_MIN(cbUsed, sizeof(pThis->abReadBuf) - pThis->offRead);
+
+ return cbUsed;
+}
+
+
+/**
+ * Advances the write position of the read buffer by the given amount of bytes.
+ *
+ * @returns nothing.
+ * @param pThis The host serial driver instance.
+ * @param cbAdv Number of bytes to advance.
+ */
+DECLINLINE(void) drvHostSerialReadBufWriteAdv(PDRVHOSTSERIAL pThis, size_t cbAdv)
+{
+ uint32_t offWrite = ASMAtomicReadU32(&pThis->offWrite);
+ offWrite = (offWrite + cbAdv) % sizeof(pThis->abReadBuf);
+ ASMAtomicWriteU32(&pThis->offWrite, offWrite);
+ ASMAtomicAddZ(&pThis->cbReadBuf, cbAdv);
+}
+
+
+/**
+ * Advances the read position of the read buffer by the given amount of bytes.
+ *
+ * @returns nothing.
+ * @param pThis The host serial driver instance.
+ * @param cbAdv Number of bytes to advance.
+ */
+DECLINLINE(void) drvHostSerialReadBufReadAdv(PDRVHOSTSERIAL pThis, size_t cbAdv)
+{
+ uint32_t offRead = ASMAtomicReadU32(&pThis->offRead);
+ offRead = (offRead + cbAdv) % sizeof(pThis->abReadBuf);
+ ASMAtomicWriteU32(&pThis->offRead, offRead);
+ ASMAtomicSubZ(&pThis->cbReadBuf, cbAdv);
+}
/* -=-=-=-=- IBase -=-=-=-=- */
@@ -162,930 +180,344 @@ static DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, co
PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARCONNECTOR, &pThis->ICharConnector);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALCONNECTOR, &pThis->ISerialConnector);
return NULL;
}
-/* -=-=-=-=- ICharConnector -=-=-=-=- */
+/* -=-=-=-=- ISerialConnector -=-=-=-=- */
-/** @interface_method_impl{PDMICHARCONNECTOR,pfnWrite} */
-static DECLCALLBACK(int) drvHostSerialWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
+/** @interface_method_impl{PDMISERIALCONNECTOR,pfnDataAvailWrNotify} */
+static DECLCALLBACK(int) drvHostSerialDataAvailWrNotify(PPDMISERIALCONNECTOR pInterface)
{
- PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
- const uint8_t *pbBuffer = (const uint8_t *)pvBuf;
-
- LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
+ PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
- for (uint32_t i = 0; i < cbWrite; i++)
- {
- if (ASMAtomicXchgBool(&pThis->fSending, true))
- return VERR_BUFFER_OVERFLOW;
+ int rc = VINF_SUCCESS;
+ bool fAvailOld = ASMAtomicXchgBool(&pThis->fAvailWrExt, true);
+ if (!fAvailOld)
+ rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
- pThis->u8SendByte = pbBuffer[i];
- RTSemEventSignal(pThis->SendSem);
- STAM_COUNTER_INC(&pThis->StatBytesWritten);
- }
- return VINF_SUCCESS;
+ return rc;
}
-static DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
+
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnReadRdr}
+ */
+static DECLCALLBACK(int) drvHostSerialReadRdr(PPDMISERIALCONNECTOR pInterface, void *pvBuf,
+ size_t cbRead, size_t *pcbRead)
{
- PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- struct termios *termiosSetup;
- int baud_rate;
-#elif defined(RT_OS_WINDOWS)
- LPDCB comSetup;
-#endif
+ PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
+ int rc = VINF_SUCCESS;
+ uint8_t *pbDst = (uint8_t *)pvBuf;
+ size_t cbReadAll = 0;
- LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
+ do
+ {
+ void *pvSrc = NULL;
+ size_t cbThisRead = RT_MIN(drvHostSerialReadBufGetRead(pThis, &pvSrc), cbRead);
+ if (cbThisRead)
+ {
+ memcpy(pbDst, pvSrc, cbThisRead);
+ cbRead -= cbThisRead;
+ pbDst += cbThisRead;
+ cbReadAll += cbThisRead;
+ drvHostSerialReadBufReadAdv(pThis, cbThisRead);
+ }
+ else
+ break;
+ } while (cbRead > 0);
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios));
+ *pcbRead = cbReadAll;
+ /* Kick the I/O thread if there is nothing to read to recalculate the poll flags. */
+ if (!drvHostSerialReadBufGetRead(pThis, NULL))
+ rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
- /* Enable receiver */
- termiosSetup->c_cflag |= (CLOCAL | CREAD);
+ STAM_COUNTER_ADD(&pThis->StatBytesRead, cbReadAll);
+ return rc;
+}
- switch (Bps)
- {
- case 50:
- baud_rate = B50;
- break;
- case 75:
- baud_rate = B75;
- break;
- case 110:
- baud_rate = B110;
- break;
- case 134:
- baud_rate = B134;
- break;
- case 150:
- baud_rate = B150;
- break;
- case 200:
- baud_rate = B200;
- break;
- case 300:
- baud_rate = B300;
- break;
- case 600:
- baud_rate = B600;
- break;
- case 1200:
- baud_rate = B1200;
- break;
- case 1800:
- baud_rate = B1800;
- break;
- case 2400:
- baud_rate = B2400;
- break;
- case 4800:
- baud_rate = B4800;
- break;
- case 9600:
- baud_rate = B9600;
- break;
- case 19200:
- baud_rate = B19200;
- break;
- case 38400:
- baud_rate = B38400;
- break;
- case 57600:
- baud_rate = B57600;
- break;
- case 115200:
- baud_rate = B115200;
- break;
- default:
-#ifdef RT_OS_LINUX
- struct serial_struct serialStruct;
- if (ioctl(RTFileToNative(pThis->hDeviceFile), TIOCGSERIAL, &serialStruct) != -1)
- {
- serialStruct.custom_divisor = serialStruct.baud_base / Bps;
- if (!serialStruct.custom_divisor)
- serialStruct.custom_divisor = 1;
- serialStruct.flags &= ~ASYNC_SPD_MASK;
- serialStruct.flags |= ASYNC_SPD_CUST;
- ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSSERIAL, &serialStruct);
- baud_rate = B38400;
- }
- else
- baud_rate = B9600;
-#else /* !RT_OS_LINUX */
- baud_rate = B9600;
-#endif /* !RT_OS_LINUX */
- }
- cfsetispeed(termiosSetup, baud_rate);
- cfsetospeed(termiosSetup, baud_rate);
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgParams}
+ */
+static DECLCALLBACK(int) drvHostSerialChgParams(PPDMISERIALCONNECTOR pInterface, uint32_t uBps,
+ PDMSERIALPARITY enmParity, unsigned cDataBits,
+ PDMSERIALSTOPBITS enmStopBits)
+{
+ PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
+ RTSERIALPORTCFG Cfg;
+
+ Cfg.uBaudRate = uBps;
- switch (chParity)
+ switch (enmParity)
{
- case 'E':
- termiosSetup->c_cflag |= PARENB;
+ case PDMSERIALPARITY_EVEN:
+ Cfg.enmParity = RTSERIALPORTPARITY_EVEN;
break;
- case 'O':
- termiosSetup->c_cflag |= (PARENB | PARODD);
+ case PDMSERIALPARITY_ODD:
+ Cfg.enmParity = RTSERIALPORTPARITY_ODD;
break;
- case 'N':
+ case PDMSERIALPARITY_NONE:
+ Cfg.enmParity = RTSERIALPORTPARITY_NONE;
break;
- default:
+ case PDMSERIALPARITY_MARK:
+ Cfg.enmParity = RTSERIALPORTPARITY_MARK;
+ break;
+ case PDMSERIALPARITY_SPACE:
+ Cfg.enmParity = RTSERIALPORTPARITY_SPACE;
break;
+ default:
+ AssertMsgFailed(("Unsupported parity setting %d\n", enmParity)); /* Should not happen. */
+ Cfg.enmParity = RTSERIALPORTPARITY_NONE;
}
switch (cDataBits)
{
case 5:
- termiosSetup->c_cflag |= CS5;
+ Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
break;
case 6:
- termiosSetup->c_cflag |= CS6;
+ Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
break;
case 7:
- termiosSetup->c_cflag |= CS7;
+ Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
break;
case 8:
- termiosSetup->c_cflag |= CS8;
+ Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
break;
default:
- break;
+ AssertMsgFailed(("Unsupported data bit count %u\n", cDataBits)); /* Should not happen. */
+ Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
}
- switch (cStopBits)
+ switch (enmStopBits)
{
- case 2:
- termiosSetup->c_cflag |= CSTOPB;
- default:
+ case PDMSERIALSTOPBITS_ONE:
+ Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
break;
- }
-
- /* set serial port to raw input */
- termiosSetup->c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ECHOK | ISIG | IEXTEN);
-
- tcsetattr(RTFileToNative(pThis->hDeviceFile), TCSANOW, termiosSetup);
- RTMemTmpFree(termiosSetup);
-
-#ifdef RT_OS_LINUX
- /*
- * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
- * waiting in ioctl for a modem status change then 8250.c wrongly disables
- * modem irqs and so the monitor thread never gets released. The workaround
- * is to send a signal after each tcsetattr.
- */
- if (RT_LIKELY(pThis->pMonitorThread != NULL))
- RTThreadPoke(pThis->pMonitorThread->Thread);
-#endif
-
-#elif defined(RT_OS_WINDOWS)
- comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
-
- comSetup->DCBlength = sizeof(DCB);
-
- switch (Bps)
- {
- case 110:
- comSetup->BaudRate = CBR_110;
- break;
- case 300:
- comSetup->BaudRate = CBR_300;
- break;
- case 600:
- comSetup->BaudRate = CBR_600;
+ case PDMSERIALSTOPBITS_ONEPOINTFIVE:
+ Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
break;
- case 1200:
- comSetup->BaudRate = CBR_1200;
- break;
- case 2400:
- comSetup->BaudRate = CBR_2400;
- break;
- case 4800:
- comSetup->BaudRate = CBR_4800;
- break;
- case 9600:
- comSetup->BaudRate = CBR_9600;
- break;
- case 14400:
- comSetup->BaudRate = CBR_14400;
- break;
- case 19200:
- comSetup->BaudRate = CBR_19200;
- break;
- case 38400:
- comSetup->BaudRate = CBR_38400;
- break;
- case 57600:
- comSetup->BaudRate = CBR_57600;
- break;
- case 115200:
- comSetup->BaudRate = CBR_115200;
+ case PDMSERIALSTOPBITS_TWO:
+ Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
break;
default:
- comSetup->BaudRate = CBR_9600;
+ AssertMsgFailed(("Unsupported stop bit count %d\n", enmStopBits)); /* Should not happen. */
+ Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
}
- comSetup->fBinary = TRUE;
- comSetup->fOutxCtsFlow = FALSE;
- comSetup->fOutxDsrFlow = FALSE;
- comSetup->fDtrControl = DTR_CONTROL_DISABLE;
- comSetup->fDsrSensitivity = FALSE;
- comSetup->fTXContinueOnXoff = TRUE;
- comSetup->fOutX = FALSE;
- comSetup->fInX = FALSE;
- comSetup->fErrorChar = FALSE;
- comSetup->fNull = FALSE;
- comSetup->fRtsControl = RTS_CONTROL_DISABLE;
- comSetup->fAbortOnError = FALSE;
- comSetup->wReserved = 0;
- comSetup->XonLim = 5;
- comSetup->XoffLim = 5;
- comSetup->ByteSize = cDataBits;
-
- switch (chParity)
- {
- case 'E':
- comSetup->Parity = EVENPARITY;
- break;
- case 'O':
- comSetup->Parity = ODDPARITY;
- break;
- case 'N':
- comSetup->Parity = NOPARITY;
- break;
- default:
- break;
- }
-
- switch (cStopBits)
- {
- case 1:
- comSetup->StopBits = ONESTOPBIT;
- break;
- case 2:
- comSetup->StopBits = TWOSTOPBITS;
- break;
- default:
- break;
- }
-
- comSetup->XonChar = 0;
- comSetup->XoffChar = 0;
- comSetup->ErrorChar = 0;
- comSetup->EofChar = 0;
- comSetup->EvtChar = 0;
-
- SetCommState(pThis->hDeviceFile, comSetup);
- RTMemTmpFree(comSetup);
-#endif /* RT_OS_WINDOWS */
-
- return VINF_SUCCESS;
+ return RTSerialPortCfgSet(pThis->hSerialPort, &Cfg, NULL);
}
-/* -=-=-=-=- receive thread -=-=-=-=- */
/**
- * Send thread loop.
- *
- * @returns VINF_SUCCESS.
- * @param pDrvIns PDM driver instance data.
- * @param pThread The PDM thread data.
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgModemLines}
*/
-static DECLCALLBACK(int) drvHostSerialSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
+static DECLCALLBACK(int) drvHostSerialChgModemLines(PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)
{
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
-
- if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
- return VINF_SUCCESS;
-
-#ifdef RT_OS_WINDOWS
- /* Make sure that the halt event semaphore is reset. */
- DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
+ PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
- HANDLE haWait[2];
- haWait[0] = pThis->hEventSend;
- haWait[1] = pThis->hHaltEventSem;
-#endif
+ uint32_t fClear = 0;
+ uint32_t fSet = 0;
- while (pThread->enmState == PDMTHREADSTATE_RUNNING)
- {
- int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT);
- AssertRCBreak(rc);
+ if (fRts)
+ fSet |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
+ else
+ fClear |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
- /*
- * Write the character to the host device.
- */
- while (pThread->enmState == PDMTHREADSTATE_RUNNING)
- {
- /* copy the send queue so we get a linear buffer with the maximal size. */
- uint8_t ch = pThis->u8SendByte;
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
+ if (fDtr)
+ fSet |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
+ else
+ fClear |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
- size_t cbWritten;
- rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
- if (rc == VERR_TRY_AGAIN)
- cbWritten = 0;
- if (cbWritten < 1 && (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN))
- {
- /* ok, block till the device is ready for more (O_NONBLOCK) effect. */
- rc = VINF_SUCCESS;
- while (pThread->enmState == PDMTHREADSTATE_RUNNING)
- {
- /* wait */
- fd_set WrSet;
- FD_ZERO(&WrSet);
- FD_SET(RTFileToNative(pThis->hDeviceFile), &WrSet);
- fd_set XcptSet;
- FD_ZERO(&XcptSet);
- FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
-# ifdef DEBUG
- uint64_t u64Now = RTTimeMilliTS();
-# endif
- rc = select(RTFileToNative(pThis->hDeviceFile) + 1, NULL, &WrSet, &XcptSet, NULL);
- /** @todo check rc? */
-
-# ifdef DEBUG
- Log2(("select wait for %dms\n", RTTimeMilliTS() - u64Now));
-# endif
- /* try write more */
- rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten);
- if (rc == VERR_TRY_AGAIN)
- cbWritten = 0;
- else if (RT_FAILURE(rc))
- break;
- else if (cbWritten >= 1)
- break;
- rc = VINF_SUCCESS;
- } /* wait/write loop */
- }
+ return RTSerialPortChgStatusLines(pThis->hSerialPort, fClear, fSet);
+}
-#elif defined(RT_OS_WINDOWS)
- /* perform an overlapped write operation. */
- DWORD cbWritten;
- memset(&pThis->overlappedSend, 0, sizeof(pThis->overlappedSend));
- pThis->overlappedSend.hEvent = pThis->hEventSend;
- if (!WriteFile(pThis->hDeviceFile, &ch, 1, &cbWritten, &pThis->overlappedSend))
- {
- dwRet = GetLastError();
- if (dwRet == ERROR_IO_PENDING)
- {
- /*
- * write blocked, wait for completion or wakeup...
- */
- dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE);
- if (dwRet != WAIT_OBJECT_0)
- {
- AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
- break;
- }
- }
- else
- rc = RTErrConvertFromWin32(dwRet);
- }
-#endif /* RT_OS_WINDOWS */
- if (RT_FAILURE(rc))
- {
- LogRel(("HostSerial#%d: Serial Write failed with %Rrc; terminating send thread\n", pDrvIns->iInstance, rc));
- return rc;
- }
- ASMAtomicXchgBool(&pThis->fSending, false);
- break;
- } /* write loop */
- }
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgBrk}
+ */
+static DECLCALLBACK(int) drvHostSerialChgBrk(PPDMISERIALCONNECTOR pInterface, bool fBrk)
+{
+ PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
- return VINF_SUCCESS;
+ return RTSerialPortChgBreakCondition(pThis->hSerialPort, fBrk);
}
+
/**
- * Unblock the send thread so it can respond to a state change.
- *
- * @returns a VBox status code.
- * @param pDrvIns The driver instance.
- * @param pThread The send thread.
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnQueryStsLines}
*/
-static DECLCALLBACK(int) drvHostSerialWakeupSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
+static DECLCALLBACK(int) drvHostSerialQueryStsLines(PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)
{
- RT_NOREF(pThread);
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
- int rc;
-
- rc = RTSemEventSignal(pThis->SendSem);
- if (RT_FAILURE(rc))
- return rc;
-
-#ifdef RT_OS_WINDOWS
- if (!SetEvent(pThis->hHaltEventSem))
- return RTErrConvertFromWin32(GetLastError());
-#endif
+ PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
- return VINF_SUCCESS;
+ return RTSerialPortQueryStatusLines(pThis->hSerialPort, pfStsLines);
}
-/* -=-=-=-=- receive thread -=-=-=-=- */
+
+/* -=-=-=-=- I/O thread -=-=-=-=- */
/**
- * Receive thread loop.
- *
- * This thread pushes data from the host serial device up the driver
- * chain toward the serial device.
+ * I/O thread loop.
*
* @returns VINF_SUCCESS.
* @param pDrvIns PDM driver instance data.
* @param pThread The PDM thread data.
*/
-static DECLCALLBACK(int) drvHostSerialRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
+static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
- uint8_t abBuffer[256];
- uint8_t *pbBuffer = NULL;
- size_t cbRemaining = 0; /* start by reading host data */
- int rc = VINF_SUCCESS;
- int rcThread = VINF_SUCCESS;
if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
return VINF_SUCCESS;
-#ifdef RT_OS_WINDOWS
- /* Make sure that the halt event semaphore is reset. */
- DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);
-
- HANDLE ahWait[2];
- ahWait[0] = pThis->hEventRecv;
- ahWait[1] = pThis->hHaltEventSem;
-#endif
-
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
- if (!cbRemaining)
- {
- /* Get a block of data from the host serial device. */
-
-#if defined(RT_OS_DARWIN) /* poll is broken on x86 darwin, returns POLLNVAL. */
- fd_set RdSet;
- FD_ZERO(&RdSet);
- FD_SET(RTFileToNative(pThis->hDeviceFileR), &RdSet);
- FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet);
- fd_set XcptSet;
- FD_ZERO(&XcptSet);
- FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet);
- FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet);
-# if 1 /* it seems like this select is blocking the write... */
- rc = select(RT_MAX(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR)) + 1,
- &RdSet, NULL, &XcptSet, NULL);
-# else
- struct timeval tv = { 0, 1000 };
- rc = select(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR) + 1,
- &RdSet, NULL, &XcptSet, &tv);
-# endif
- if (rc == -1)
- {
- int err = errno;
- rcThread = RTErrConvertFromErrno(err);
- LogRel(("HostSerial#%d: select failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
- break;
- }
+ uint32_t fEvtFlags = RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED | RTSERIALPORT_EVT_F_BREAK_DETECTED;
- /* this might have changed in the meantime */
- if (pThread->enmState != PDMTHREADSTATE_RUNNING)
- break;
- if (rc == 0)
- continue;
+ if (!pThis->fAvailWrInt)
+ pThis->fAvailWrInt = ASMAtomicXchgBool(&pThis->fAvailWrExt, false);
- /* drain the wakeup pipe */
- size_t cbRead;
- if ( FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet)
- || FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet))
- {
- rc = RTPipeRead(pThis->hWakeupPipeR, abBuffer, 1, &cbRead);
- if (RT_FAILURE(rc))
- {
- LogRel(("HostSerial#%d: draining the wakeup pipe failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
- rcThread = rc;
- break;
- }
- continue;
- }
+ /* Wait until there is room again if there is anyting to send. */
+ if ( pThis->fAvailWrInt
+ || pThis->cbTxUsed)
+ fEvtFlags |= RTSERIALPORT_EVT_F_DATA_TX;
- /* read data from the serial port. */
- rc = RTFileRead(pThis->hDeviceFileR, abBuffer, sizeof(abBuffer), &cbRead);
- if (RT_FAILURE(rc))
- {
- LogRel(("HostSerial#%d: (1) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
- rcThread = rc;
- break;
- }
- cbRemaining = cbRead;
-
-#elif defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
-
- size_t cbRead;
- struct pollfd aFDs[2];
- aFDs[0].fd = RTFileToNative(pThis->hDeviceFile);
- aFDs[0].events = POLLIN;
- aFDs[0].revents = 0;
- aFDs[1].fd = RTPipeToNative(pThis->hWakeupPipeR);
- aFDs[1].events = POLLIN | POLLERR | POLLHUP;
- aFDs[1].revents = 0;
- rc = poll(aFDs, RT_ELEMENTS(aFDs), -1);
- if (rc < 0)
- {
- int err = errno;
- if (err == EINTR)
- {
- /*
- * EINTR errors should be harmless, even if they are not supposed to occur in our setup.
- */
- Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, err, strerror(err)));
- RTThreadYield();
- continue;
- }
-
- rcThread = RTErrConvertFromErrno(err);
- LogRel(("HostSerial#%d: poll failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread));
- break;
- }
- /* this might have changed in the meantime */
- if (pThread->enmState != PDMTHREADSTATE_RUNNING)
- break;
- if (rc > 0 && aFDs[1].revents)
- {
- if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
- break;
- /* notification to terminate -- drain the pipe */
- RTPipeRead(pThis->hWakeupPipeR, &abBuffer, 1, &cbRead);
- continue;
- }
- rc = RTFileRead(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
- if (RT_FAILURE(rc))
- {
- /* don't terminate worker thread when data unavailable */
- if (rc == VERR_TRY_AGAIN)
- continue;
+ /* Try to receive more if there is still room. */
+ if (drvHostSerialReadBufGetWrite(pThis, NULL) > 0)
+ fEvtFlags |= RTSERIALPORT_EVT_F_DATA_RX;
- LogRel(("HostSerial#%d: (2) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
- rcThread = rc;
- break;
- }
- cbRemaining = cbRead;
-
-#elif defined(RT_OS_WINDOWS)
-
- DWORD dwEventMask = 0;
- DWORD dwNumberOfBytesTransferred;
-
- memset(&pThis->overlappedRecv, 0, sizeof(pThis->overlappedRecv));
- pThis->overlappedRecv.hEvent = pThis->hEventRecv;
-
- if (!WaitCommEvent(pThis->hDeviceFile, &dwEventMask, &pThis->overlappedRecv))
+ uint32_t fEvtsRecv = 0;
+ int rc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_TX)
{
- dwRet = GetLastError();
- if (dwRet == ERROR_IO_PENDING)
+ if (pThis->fAvailWrInt)
{
- dwRet = WaitForMultipleObjects(2, ahWait, FALSE, INFINITE);
- if (dwRet != WAIT_OBJECT_0)
+ /* Stuff as much data into the TX buffer as we can. */
+ size_t cbToFetch = RT_ELEMENTS(pThis->abTxBuf) - pThis->cbTxUsed;
+ size_t cbFetched = 0;
+ rc = pThis->pDrvSerialPort->pfnReadWr(pThis->pDrvSerialPort, &pThis->abTxBuf[pThis->cbTxUsed], cbToFetch,
+ &cbFetched);
+ AssertRC(rc);
+
+ if (cbFetched > 0)
+ pThis->cbTxUsed += cbFetched;
+ else
{
- /* notification to terminate */
- AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n"));
- break;
+ /* There is no data available anymore. */
+ pThis->fAvailWrInt = false;
}
}
- else
- {
- rcThread = RTErrConvertFromWin32(dwRet);
- LogRel(("HostSerial#%d: Wait failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
- break;
- }
- }
- /* this might have changed in the meantime */
- if (pThread->enmState != PDMTHREADSTATE_RUNNING)
- break;
- /* Check the event */
- if (dwEventMask & EV_RXCHAR)
- {
- if (!ReadFile(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &pThis->overlappedRecv))
+ if (pThis->cbTxUsed)
{
- dwRet = GetLastError();
- if (dwRet == ERROR_IO_PENDING)
+ size_t cbProcessed = 0;
+ rc = RTSerialPortWriteNB(pThis->hSerialPort, &pThis->abTxBuf[0], pThis->cbTxUsed, &cbProcessed);
+ if (RT_SUCCESS(rc))
{
- if (GetOverlappedResult(pThis->hDeviceFile, &pThis->overlappedRecv, &dwNumberOfBytesTransferred, TRUE))
- dwRet = NO_ERROR;
+ pThis->cbTxUsed -= cbProcessed;
+ if (pThis->cbTxUsed)
+ {
+ /* Move the data in the TX buffer to the front to fill the end again. */
+ memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed);
+ }
else
- dwRet = GetLastError();
+ pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort);
+ STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbProcessed);
}
- if (dwRet != NO_ERROR)
+ else
{
- rcThread = RTErrConvertFromWin32(dwRet);
- LogRel(("HostSerial#%d: Read failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread));
+ LogRelMax(10, ("HostSerial#%d: Sending data failed even though the serial port is marked as writeable (rc=%Rrc)\n",
+ pThis->pDrvIns->iInstance, rc));
break;
}
}
- cbRemaining = dwNumberOfBytesTransferred;
}
- else if (dwEventMask & EV_BREAK)
+
+ if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_RX)
{
- Log(("HostSerial#%d: Detected break\n"));
- rc = pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort);
+ void *pvDst = NULL;
+ size_t cbToRead = drvHostSerialReadBufGetWrite(pThis, &pvDst);
+ size_t cbRead = 0;
+ rc = RTSerialPortReadNB(pThis->hSerialPort, pvDst, cbToRead, &cbRead);
+ if (RT_SUCCESS(rc))
+ {
+ drvHostSerialReadBufWriteAdv(pThis, cbRead);
+ /* Notify the device/driver above. */
+ rc = pThis->pDrvSerialPort->pfnDataAvailRdrNotify(pThis->pDrvSerialPort, cbRead);
+ AssertRC(rc);
+ }
+ else
+ LogRelMax(10, ("HostSerial#%d: Reading data failed even though the serial port is marked as readable (rc=%Rrc)\n",
+ pThis->pDrvIns->iInstance, rc));
}
- else
+
+ if (fEvtsRecv & RTSERIALPORT_EVT_F_BREAK_DETECTED)
+ pThis->pDrvSerialPort->pfnNotifyBrk(pThis->pDrvSerialPort);
+
+ if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
{
/* The status lines have changed. Notify the device. */
- DWORD dwNewStatusLinesState = 0;
- uint32_t uNewStatusLinesState = 0;
-
- /* Get the new state */
- if (GetCommModemStatus(pThis->hDeviceFile, &dwNewStatusLinesState))
+ uint32_t fStsLines = 0;
+ rc = RTSerialPortQueryStatusLines(pThis->hSerialPort, &fStsLines);
+ if (RT_SUCCESS(rc))
{
- if (dwNewStatusLinesState & MS_RLSD_ON)
- uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DCD;
- if (dwNewStatusLinesState & MS_RING_ON)
- uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_RI;
- if (dwNewStatusLinesState & MS_DSR_ON)
- uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DSR;
- if (dwNewStatusLinesState & MS_CTS_ON)
- uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_CTS;
- rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, uNewStatusLinesState);
+ uint32_t fPdmStsLines = 0;
+
+ if (fStsLines & RTSERIALPORT_STS_LINE_DCD)
+ fPdmStsLines |= PDMISERIALPORT_STS_LINE_DCD;
+ if (fStsLines & RTSERIALPORT_STS_LINE_RI)
+ fPdmStsLines |= PDMISERIALPORT_STS_LINE_RI;
+ if (fStsLines & RTSERIALPORT_STS_LINE_DSR)
+ fPdmStsLines |= PDMISERIALPORT_STS_LINE_DSR;
+ if (fStsLines & RTSERIALPORT_STS_LINE_CTS)
+ fPdmStsLines |= PDMISERIALPORT_STS_LINE_CTS;
+
+ rc = pThis->pDrvSerialPort->pfnNotifyStsLinesChanged(pThis->pDrvSerialPort, fPdmStsLines);
if (RT_FAILURE(rc))
{
/* Notifying device failed, continue but log it */
- LogRel(("HostSerial#%d: Notifying device failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
+ LogRelMax(10, ("HostSerial#%d: Notifying device about changed status lines failed with error %Rrc; continuing.\n",
+ pDrvIns->iInstance, rc));
}
}
else
- {
- /* Getting new state failed, continue but log it */
- LogRel(("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError())));
- }
+ LogRelMax(10, ("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
}
-#endif
- Log(("Read %d bytes.\n", cbRemaining));
- pbBuffer = abBuffer;
+ if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED)
+ LogRel(("HostSerial#%d: Status line monitoring failed at a lower level and is disabled\n", pDrvIns->iInstance));
}
- else
+ else if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
{
- /* Send data to the guest. */
- size_t cbProcessed = cbRemaining;
- rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbBuffer, &cbProcessed);
- if (RT_SUCCESS(rc))
- {
- Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
- pbBuffer += cbProcessed;
- cbRemaining -= cbProcessed;
- STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed);
- }
- else if (rc == VERR_TIMEOUT)
- {
- /* Normal case, just means that the guest didn't accept a new
- * character before the timeout elapsed. Just retry. */
- rc = VINF_SUCCESS;
- }
- else
- {
- LogRel(("HostSerial#%d: NotifyRead failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc));
- rcThread = rc;
- break;
- }
+ /* Getting interrupted or running into a timeout are no error conditions. */
+ rc = VINF_SUCCESS;
}
}
- return rcThread;
-}
-
-/**
- * Unblock the receive thread so it can respond to a state change.
- *
- * @returns a VBox status code.
- * @param pDrvIns The driver instance.
- * @param pThread The receive thread.
- */
-static DECLCALLBACK(int) drvHostSerialWakeupRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- RT_NOREF(pThread);
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- size_t cbIgnored;
- return RTPipeWrite(pThis->hWakeupPipeW, "", 1, &cbIgnored);
-
-#elif defined(RT_OS_WINDOWS)
- if (!SetEvent(pThis->hHaltEventSem))
- return RTErrConvertFromWin32(GetLastError());
return VINF_SUCCESS;
-#else
-# error adapt me!
-#endif
}
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
-/* -=-=-=-=- Monitor thread -=-=-=-=- */
/**
- * Monitor thread loop.
- *
- * This thread monitors the status lines and notifies the device
- * if they change.
- *
- * @returns VINF_SUCCESS.
- * @param pDrvIns PDM driver instance data.
- * @param pThread The PDM thread data.
- */
-static DECLCALLBACK(int) drvHostSerialMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
- unsigned long const uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
-#ifdef RT_OS_LINUX
- bool fPoll = false;
-#endif
-
- if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
- return VINF_SUCCESS;
-
- do
- {
- unsigned int statusLines;
-
- /*
- * Get the status line state.
- */
- int rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &statusLines);
- if (rcPsx < 0)
- {
- PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
- N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"),
- pThis->pszDevicePath, RTErrConvertFromErrno(errno));
- break;
- }
-
- uint32_t newStatusLine = 0;
-
- if (statusLines & TIOCM_CAR)
- newStatusLine |= PDMICHARPORT_STATUS_LINES_DCD;
- if (statusLines & TIOCM_RNG)
- newStatusLine |= PDMICHARPORT_STATUS_LINES_RI;
- if (statusLines & TIOCM_DSR)
- newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR;
- if (statusLines & TIOCM_CTS)
- newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS;
- pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine);
-
- if (PDMTHREADSTATE_RUNNING != pThread->enmState)
- break;
-
-# ifdef RT_OS_LINUX
- /*
- * Wait for status line change.
- *
- * XXX In Linux, if a thread calls tcsetattr while the monitor thread is
- * waiting in ioctl for a modem status change then 8250.c wrongly disables
- * modem irqs and so the monitor thread never gets released. The workaround
- * is to send a signal after each tcsetattr.
- *
- * TIOCMIWAIT doesn't work for the DSR line with TIOCM_DSR set
- * (see http://lxr.linux.no/#linux+v4.7/drivers/usb/class/cdc-acm.c#L949)
- * However as it is possible to query the line state we will not just clear
- * the TIOCM_DSR bit from the lines to check but resort to the polling
- * approach just like on other hosts.
- */
- if (!fPoll)
- {
- rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMIWAIT, uStatusLinesToCheck);
- if (rcPsx < 0 && errno != EINTR)
- {
- LogRel(("Serial#%u: Failed to wait for status line change with rcPsx=%d errno=%d, switch to polling\n",
- pDrvIns->iInstance, rcPsx, errno));
- fPoll = true;
- pThis->fStatusLines = statusLines;
- }
- }
- else
- {
- /* Poll for status line change. */
- if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
- PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
- pThis->fStatusLines = statusLines;
- }
-# else
- /* Poll for status line change. */
- if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck))
- PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */
- pThis->fStatusLines = statusLines;
-# endif
- } while (PDMTHREADSTATE_RUNNING == pThread->enmState);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Unblock the monitor thread so it can respond to a state change.
- * We need to execute this code exactly once during initialization.
- * But we don't want to block --- therefore this dedicated thread.
+ * Unblock the send thread so it can respond to a state change.
*
* @returns a VBox status code.
* @param pDrvIns The driver instance.
* @param pThread The send thread.
*/
-static DECLCALLBACK(int) drvHostSerialWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
+static DECLCALLBACK(int) drvHostSerialWakeupIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
-# ifdef RT_OS_LINUX
+ RT_NOREF(pThread);
PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
- int rc = VINF_SUCCESS;
-
- rc = RTThreadPoke(pThread->Thread);
- if (RT_FAILURE(rc))
- PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
- N_("Suspending serial monitor thread failed for serial device '%s' (%Rrc). The shutdown may take longer than expected"),
- pThis->pszDevicePath, RTErrConvertFromErrno(rc));
-
-# else /* !RT_OS_LINUX*/
-
- /* In polling mode there is nobody to wake up (PDMThread will cancel the sleep). */
- NOREF(pDrvIns);
- NOREF(pThread);
-
-# endif /* RT_OS_LINUX */
- return VINF_SUCCESS;
+ return RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
}
-#endif /* RT_OS_LINUX || RT_OS_DARWIN || RT_OS_SOLARIS */
-
-/**
- * Set the modem lines.
- *
- * @returns VBox status code
- * @param pInterface Pointer to the interface structure.
- * @param RequestToSend Set to true if this control line should be made active.
- * @param DataTerminalReady Set to true if this control line should be made active.
- */
-static DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool RequestToSend, bool DataTerminalReady)
-{
- PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
-
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- int modemStateSet = 0;
- int modemStateClear = 0;
-
- if (RequestToSend)
- modemStateSet |= TIOCM_RTS;
- else
- modemStateClear |= TIOCM_RTS;
-
- if (DataTerminalReady)
- modemStateSet |= TIOCM_DTR;
- else
- modemStateClear |= TIOCM_DTR;
- if (modemStateSet)
- ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIS, &modemStateSet);
-
- if (modemStateClear)
- ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIC, &modemStateClear);
-
-#elif defined(RT_OS_WINDOWS)
- if (RequestToSend)
- EscapeCommFunction(pThis->hDeviceFile, SETRTS);
- else
- EscapeCommFunction(pThis->hDeviceFile, CLRRTS);
-
- if (DataTerminalReady)
- EscapeCommFunction(pThis->hDeviceFile, SETDTR);
- else
- EscapeCommFunction(pThis->hDeviceFile, CLRDTR);
-
-#endif
-
- return VINF_SUCCESS;
-}
-
-/**
- * Sets the TD line into break condition.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param fBreak Set to true to let the device send a break false to put into normal operation.
- * @thread Any thread.
- */
-static DECLCALLBACK(int) drvHostSerialSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak)
-{
- PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
-
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- if (fBreak)
- ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSBRK);
- else
- ioctl(RTFileToNative(pThis->hDeviceFile), TIOCCBRK);
-
-#elif defined(RT_OS_WINDOWS)
- if (fBreak)
- SetCommBreak(pThis->hDeviceFile);
- else
- ClearCommBreak(pThis->hDeviceFile);
-#endif
-
- return VINF_SUCCESS;
-}
/* -=-=-=-=- driver interface -=-=-=-=- */
@@ -1099,49 +531,16 @@ static DECLCALLBACK(int) drvHostSerialSetBreak(PPDMICHARCONNECTOR pInterface, bo
*/
static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
{
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
-
- /* Empty the send queue */
- if (pThis->SendSem != NIL_RTSEMEVENT)
- {
- RTSemEventDestroy(pThis->SendSem);
- pThis->SendSem = NIL_RTSEMEVENT;
- }
-
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
-
- int rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc);
- pThis->hWakeupPipeW = NIL_RTPIPE;
- rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc);
- pThis->hWakeupPipeR = NIL_RTPIPE;
-# if defined(RT_OS_DARWIN)
- if (pThis->hDeviceFileR != NIL_RTFILE)
- {
- if (pThis->hDeviceFileR != pThis->hDeviceFile)
- {
- rc = RTFileClose(pThis->hDeviceFileR);
- AssertRC(rc);
- }
- pThis->hDeviceFileR = NIL_RTFILE;
- }
-# endif
- if (pThis->hDeviceFile != NIL_RTFILE)
+ if (pThis->hSerialPort != NIL_RTSERIALPORT)
{
- rc = RTFileClose(pThis->hDeviceFile); AssertRC(rc);
- pThis->hDeviceFile = NIL_RTFILE;
+ RTSerialPortClose(pThis->hSerialPort);
+ pThis->hSerialPort = NIL_RTSERIALPORT;
}
-#elif defined(RT_OS_WINDOWS)
- CloseHandle(pThis->hEventRecv);
- CloseHandle(pThis->hEventSend);
- CancelIo(pThis->hDeviceFile);
- CloseHandle(pThis->hDeviceFile);
-
-#endif
-
if (pThis->pszDevicePath)
{
MMR3HeapFree(pThis->pszDevicePath);
@@ -1149,6 +548,7 @@ static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
}
}
+
/**
* Construct a char driver instance.
*
@@ -1164,26 +564,23 @@ static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pC
/*
* Init basic data members and interfaces.
*/
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- pThis->hDeviceFile = NIL_RTFILE;
-# ifdef RT_OS_DARWIN
- pThis->hDeviceFileR = NIL_RTFILE;
-# endif
- pThis->hWakeupPipeR = NIL_RTPIPE;
- pThis->hWakeupPipeW = NIL_RTPIPE;
-#elif defined(RT_OS_WINDOWS)
- pThis->hEventRecv = INVALID_HANDLE_VALUE;
- pThis->hEventSend = INVALID_HANDLE_VALUE;
- pThis->hDeviceFile = INVALID_HANDLE_VALUE;
-#endif
- pThis->SendSem = NIL_RTSEMEVENT;
+ pThis->pDrvIns = pDrvIns;
+ pThis->hSerialPort = NIL_RTSERIALPORT;
+ pThis->fAvailWrExt = false;
+ pThis->fAvailWrInt = false;
+ pThis->cbTxUsed = 0;
+ pThis->offWrite = 0;
+ pThis->offRead = 0;
+ pThis->cbReadBuf = 0;
/* IBase. */
- pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
- /* ICharConnector. */
- pThis->ICharConnector.pfnWrite = drvHostSerialWrite;
- pThis->ICharConnector.pfnSetParameters = drvHostSerialSetParameters;
- pThis->ICharConnector.pfnSetModemLines = drvHostSerialSetModemLines;
- pThis->ICharConnector.pfnSetBreak = drvHostSerialSetBreak;
+ pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
+ /* ISerialConnector. */
+ pThis->ISerialConnector.pfnDataAvailWrNotify = drvHostSerialDataAvailWrNotify;
+ pThis->ISerialConnector.pfnReadRdr = drvHostSerialReadRdr;
+ pThis->ISerialConnector.pfnChgParams = drvHostSerialChgParams;
+ pThis->ISerialConnector.pfnChgModemLines = drvHostSerialChgModemLines;
+ pThis->ISerialConnector.pfnChgBrk = drvHostSerialChgBrk;
+ pThis->ISerialConnector.pfnQueryStsLines = drvHostSerialQueryStsLines;
/*
* Query configuration.
@@ -1199,59 +596,21 @@ static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pC
/*
* Open the device
*/
-#ifdef RT_OS_WINDOWS
-
- pThis->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
- AssertReturn(pThis->hHaltEventSem != NULL, VERR_NO_MEMORY);
-
- pThis->hEventRecv = CreateEvent(NULL, FALSE, FALSE, NULL);
- AssertReturn(pThis->hEventRecv != NULL, VERR_NO_MEMORY);
-
- pThis->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL);
- AssertReturn(pThis->hEventSend != NULL, VERR_NO_MEMORY);
-
- HANDLE hFile = CreateFile(pThis->pszDevicePath,
- GENERIC_READ | GENERIC_WRITE,
- 0, // must be opened with exclusive access
- NULL, // no SECURITY_ATTRIBUTES structure
- OPEN_EXISTING, // must use OPEN_EXISTING
- FILE_FLAG_OVERLAPPED, // overlapped I/O
- NULL); // no template file
- if (hFile == INVALID_HANDLE_VALUE)
- rc = RTErrConvertFromWin32(GetLastError());
- else
+ uint32_t fOpenFlags = RTSERIALPORT_OPEN_F_READ
+ | RTSERIALPORT_OPEN_F_WRITE
+ | RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING
+ | RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION;
+ rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
+ if (rc == VERR_NOT_SUPPORTED)
{
- pThis->hDeviceFile = hFile;
- /* for overlapped read */
- if (!SetCommMask(hFile, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING | EV_RLSD))
- {
- LogRel(("HostSerial#%d: SetCommMask failed with error %d.\n", pDrvIns->iInstance, GetLastError()));
- return VERR_FILE_IO_ERROR;
- }
- rc = VINF_SUCCESS;
+ /*
+ * For certain devices (or pseudo terminals) status line monitoring does not work
+ * so try again without it.
+ */
+ fOpenFlags &= ~RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING;
+ rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
}
-#else /* !RT_OS_WINDOWS */
-
- uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
-# ifdef RT_OS_LINUX
- /* This seems to be necessary on some Linux hosts, otherwise we hang here forever. */
- fOpen |= RTFILE_O_NON_BLOCK;
-# endif
- rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen);
-# ifdef RT_OS_LINUX
- /* RTFILE_O_NON_BLOCK not supported? */
- if (rc == VERR_INVALID_PARAMETER)
- rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen & ~RTFILE_O_NON_BLOCK);
-# endif
-# ifdef RT_OS_DARWIN
- if (RT_SUCCESS(rc))
- rc = RTFileOpen(&pThis->hDeviceFileR, pThis->pszDevicePath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
-# endif
-
-
-#endif /* !RT_OS_WINDOWS */
-
if (RT_FAILURE(rc))
{
AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pThis->pszDevicePath, rc));
@@ -1276,79 +635,27 @@ static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pC
}
}
- /* Set to non blocking I/O */
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
-
- fcntl(RTFileToNative(pThis->hDeviceFile), F_SETFL, O_NONBLOCK);
-# ifdef RT_OS_DARWIN
- fcntl(RTFileToNative(pThis->hDeviceFileR), F_SETFL, O_NONBLOCK);
-# endif
- rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/);
- AssertRCReturn(rc, rc);
-
-#elif defined(RT_OS_WINDOWS)
-
- /* Set the COMMTIMEOUTS to get non blocking I/O */
- COMMTIMEOUTS comTimeout;
-
- comTimeout.ReadIntervalTimeout = MAXDWORD;
- comTimeout.ReadTotalTimeoutMultiplier = 0;
- comTimeout.ReadTotalTimeoutConstant = 0;
- comTimeout.WriteTotalTimeoutMultiplier = 0;
- comTimeout.WriteTotalTimeoutConstant = 0;
-
- SetCommTimeouts(pThis->hDeviceFile, &comTimeout);
-
-#endif
-
/*
- * Get the ICharPort interface of the above driver/device.
+ * Get the ISerialPort interface of the above driver/device.
*/
- pThis->pDrvCharPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICHARPORT);
- if (!pThis->pDrvCharPort)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance);
+ pThis->pDrvSerialPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISERIALPORT);
+ if (!pThis->pDrvSerialPort)
+ return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no serial port interface above"), pDrvIns->iInstance);
/*
- * Create the receive, send and monitor threads plus the related send semaphore.
+ * Create the I/O thread.
*/
- rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pRecvThread, pThis, drvHostSerialRecvThread, drvHostSerialWakeupRecvThread, 0, RTTHREADTYPE_IO, "SerRecv");
+ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pIoThrd, pThis, drvHostSerialIoThread, drvHostSerialWakeupIoThread, 0, RTTHREADTYPE_IO, "SerIo");
if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
-
- rc = RTSemEventCreate(&pThis->SendSem);
- AssertRC(rc);
-
- rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pSendThread, pThis, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "SerSend");
- if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
-
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- /* Linux & darwin needs a separate thread which monitors the status lines. */
- int rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &pThis->fStatusLines);
- if (!rcPsx)
- {
- rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostSerialMonitorThread, drvHostSerialWakeupMonitorThread, 0, RTTHREADTYPE_IO, "SerMon");
- if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create monitor thread"), pDrvIns->iInstance);
- }
- else
- {
- /* TIOCMGET is not supported for pseudo terminals so just silently skip it. */
- if (errno != ENOTTY)
- PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail",
- N_("Trying to get the status lines state failed for serial host device '%s' (%Rrc). The device will not work properly"),
- pThis->pszDevicePath, RTErrConvertFromErrno(errno));
- }
-#endif
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create I/O thread"), pDrvIns->iInstance);
/*
* Register release statistics.
*/
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
-#ifdef RT_OS_DARWIN /* new Write code, not darwin specific. */
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSendOverflows, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes overflowed", "/Devices/HostSerial%d/SendOverflow", pDrvIns->iInstance);
-#endif
+ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
+ "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
+ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
+ "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
return VINF_SUCCESS;
}
@@ -1362,11 +669,11 @@ const PDMDRVREG g_DrvHostSerial =
PDM_DRVREG_VERSION,
/* szName */
"Host Serial",
- /* szRCMod */
+ /* szRCMod */
"",
/* szR0Mod */
"",
-/* pszDescription */
+ /* pszDescription */
"Host serial driver.",
/* fFlags */
PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
diff --git a/src/VBox/Devices/Serial/DrvHostSerialNew.cpp b/src/VBox/Devices/Serial/DrvHostSerialNew.cpp
deleted file mode 100644
index ea5c670066f..00000000000
--- a/src/VBox/Devices/Serial/DrvHostSerialNew.cpp
+++ /dev/null
@@ -1,713 +0,0 @@
-/* $Id$ */
-/** @file
- * VBox serial devices: Host serial driver
- */
-
-/*
- * Copyright (C) 2006-2018 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
-#include <VBox/vmm/pdm.h>
-#include <VBox/vmm/pdmserialifs.h>
-#include <VBox/err.h>
-
-#include <VBox/log.h>
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/file.h>
-#include <iprt/mem.h>
-#include <iprt/pipe.h>
-#include <iprt/semaphore.h>
-#include <iprt/uuid.h>
-#include <iprt/serialport.h>
-
-#include "VBoxDD.h"
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-
-/**
- * Char driver instance data.
- *
- * @implements PDMISERIALCONNECTOR
- */
-typedef struct DRVHOSTSERIAL
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to the serial port interface of the driver/device above us. */
- PPDMISERIALPORT pDrvSerialPort;
- /** Our serial interface. */
- PDMISERIALCONNECTOR ISerialConnector;
- /** I/O thread. */
- PPDMTHREAD pIoThrd;
- /** The serial port handle. */
- RTSERIALPORT hSerialPort;
- /** the device path */
- char *pszDevicePath;
-
- /** Flag whether data is available from the device/driver above as notified by the driver. */
- volatile bool fAvailWrExt;
- /** Internal copy of the flag which gets reset when there is no data anymore. */
- bool fAvailWrInt;
- /** Small send buffer. */
- uint8_t abTxBuf[16];
- /** Amount of data in the buffer. */
- size_t cbTxUsed;
-
- /** The read queue. */
- uint8_t abReadBuf[256];
- /** Current offset to write to next. */
- volatile uint32_t offWrite;
- /** Current offset into the read buffer. */
- volatile uint32_t offRead;
- /** Current amount of data in the buffer. */
- volatile size_t cbReadBuf;
-
- /** Read/write statistics */
- STAMCOUNTER StatBytesRead;
- STAMCOUNTER StatBytesWritten;
-} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
-
-
-/*********************************************************************************************************************************
-* Global Variables *
-*********************************************************************************************************************************/
-
-
-/*********************************************************************************************************************************
-* Internal Functions *
-*********************************************************************************************************************************/
-
-
-/**
- * Returns number of bytes free in the read buffer and pointer to the start of the free space
- * in the read buffer.
- *
- * @returns Number of bytes free in the buffer.
- * @param pThis The host serial driver instance.
- * @param ppv Where to return the pointer if there is still free space.
- */
-DECLINLINE(size_t) drvHostSerialReadBufGetWrite(PDRVHOSTSERIAL pThis, void **ppv)
-{
- if (ppv)
- *ppv = &pThis->abReadBuf[pThis->offWrite];
-
- size_t cbFree = sizeof(pThis->abReadBuf) - ASMAtomicReadZ(&pThis->cbReadBuf);
- if (cbFree)
- cbFree = RT_MIN(cbFree, sizeof(pThis->abReadBuf) - pThis->offWrite);
-
- return cbFree;
-}
-
-
-/**
- * Returns number of bytes used in the read buffer and pointer to the next byte to read.
- *
- * @returns Number of bytes free in the buffer.
- * @param pThis The host serial driver instance.
- * @param ppv Where to return the pointer to the next data to read.
- */
-DECLINLINE(size_t) drvHostSerialReadBufGetRead(PDRVHOSTSERIAL pThis, void **ppv)
-{
- if (ppv)
- *ppv = &pThis->abReadBuf[pThis->offRead];
-
- size_t cbUsed = ASMAtomicReadZ(&pThis->cbReadBuf);
- if (cbUsed)
- cbUsed = RT_MIN(cbUsed, sizeof(pThis->abReadBuf) - pThis->offRead);
-
- return cbUsed;
-}
-
-
-/**
- * Advances the write position of the read buffer by the given amount of bytes.
- *
- * @returns nothing.
- * @param pThis The host serial driver instance.
- * @param cbAdv Number of bytes to advance.
- */
-DECLINLINE(void) drvHostSerialReadBufWriteAdv(PDRVHOSTSERIAL pThis, size_t cbAdv)
-{
- uint32_t offWrite = ASMAtomicReadU32(&pThis->offWrite);
- offWrite = (offWrite + cbAdv) % sizeof(pThis->abReadBuf);
- ASMAtomicWriteU32(&pThis->offWrite, offWrite);
- ASMAtomicAddZ(&pThis->cbReadBuf, cbAdv);
-}
-
-
-/**
- * Advances the read position of the read buffer by the given amount of bytes.
- *
- * @returns nothing.
- * @param pThis The host serial driver instance.
- * @param cbAdv Number of bytes to advance.
- */
-DECLINLINE(void) drvHostSerialReadBufReadAdv(PDRVHOSTSERIAL pThis, size_t cbAdv)
-{
- uint32_t offRead = ASMAtomicReadU32(&pThis->offRead);
- offRead = (offRead + cbAdv) % sizeof(pThis->abReadBuf);
- ASMAtomicWriteU32(&pThis->offRead, offRead);
- ASMAtomicSubZ(&pThis->cbReadBuf, cbAdv);
-}
-
-
-/* -=-=-=-=- IBase -=-=-=-=- */
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALCONNECTOR, &pThis->ISerialConnector);
- return NULL;
-}
-
-
-/* -=-=-=-=- ISerialConnector -=-=-=-=- */
-
-/** @interface_method_impl{PDMISERIALCONNECTOR,pfnDataAvailWrNotify} */
-static DECLCALLBACK(int) drvHostSerialDataAvailWrNotify(PPDMISERIALCONNECTOR pInterface)
-{
- PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
-
- int rc = VINF_SUCCESS;
- bool fAvailOld = ASMAtomicXchgBool(&pThis->fAvailWrExt, true);
- if (!fAvailOld)
- rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnReadRdr}
- */
-static DECLCALLBACK(int) drvHostSerialReadRdr(PPDMISERIALCONNECTOR pInterface, void *pvBuf,
- size_t cbRead, size_t *pcbRead)
-{
- PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
- int rc = VINF_SUCCESS;
- uint8_t *pbDst = (uint8_t *)pvBuf;
- size_t cbReadAll = 0;
-
- do
- {
- void *pvSrc = NULL;
- size_t cbThisRead = RT_MIN(drvHostSerialReadBufGetRead(pThis, &pvSrc), cbRead);
- if (cbThisRead)
- {
- memcpy(pbDst, pvSrc, cbThisRead);
- cbRead -= cbThisRead;
- pbDst += cbThisRead;
- cbReadAll += cbThisRead;
- drvHostSerialReadBufReadAdv(pThis, cbThisRead);
- }
- else
- break;
- } while (cbRead > 0);
-
- *pcbRead = cbReadAll;
- /* Kick the I/O thread if there is nothing to read to recalculate the poll flags. */
- if (!drvHostSerialReadBufGetRead(pThis, NULL))
- rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
-
- STAM_COUNTER_ADD(&pThis->StatBytesRead, cbReadAll);
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgParams}
- */
-static DECLCALLBACK(int) drvHostSerialChgParams(PPDMISERIALCONNECTOR pInterface, uint32_t uBps,
- PDMSERIALPARITY enmParity, unsigned cDataBits,
- PDMSERIALSTOPBITS enmStopBits)
-{
- PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
- RTSERIALPORTCFG Cfg;
-
- Cfg.uBaudRate = uBps;
-
- switch (enmParity)
- {
- case PDMSERIALPARITY_EVEN:
- Cfg.enmParity = RTSERIALPORTPARITY_EVEN;
- break;
- case PDMSERIALPARITY_ODD:
- Cfg.enmParity = RTSERIALPORTPARITY_ODD;
- break;
- case PDMSERIALPARITY_NONE:
- Cfg.enmParity = RTSERIALPORTPARITY_NONE;
- break;
- case PDMSERIALPARITY_MARK:
- Cfg.enmParity = RTSERIALPORTPARITY_MARK;
- break;
- case PDMSERIALPARITY_SPACE:
- Cfg.enmParity = RTSERIALPORTPARITY_SPACE;
- break;
- default:
- AssertMsgFailed(("Unsupported parity setting %d\n", enmParity)); /* Should not happen. */
- Cfg.enmParity = RTSERIALPORTPARITY_NONE;
- }
-
- switch (cDataBits)
- {
- case 5:
- Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
- break;
- case 6:
- Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
- break;
- case 7:
- Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
- break;
- case 8:
- Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
- break;
- default:
- AssertMsgFailed(("Unsupported data bit count %u\n", cDataBits)); /* Should not happen. */
- Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
- }
-
- switch (enmStopBits)
- {
- case PDMSERIALSTOPBITS_ONE:
- Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
- break;
- case PDMSERIALSTOPBITS_ONEPOINTFIVE:
- Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
- break;
- case PDMSERIALSTOPBITS_TWO:
- Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
- break;
- default:
- AssertMsgFailed(("Unsupported stop bit count %d\n", enmStopBits)); /* Should not happen. */
- Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
- }
-
- return RTSerialPortCfgSet(pThis->hSerialPort, &Cfg, NULL);
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgModemLines}
- */
-static DECLCALLBACK(int) drvHostSerialChgModemLines(PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)
-{
- PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
-
- uint32_t fClear = 0;
- uint32_t fSet = 0;
-
- if (fRts)
- fSet |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
- else
- fClear |= RTSERIALPORT_CHG_STS_LINES_F_RTS;
-
- if (fDtr)
- fSet |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
- else
- fClear |= RTSERIALPORT_CHG_STS_LINES_F_DTR;
-
- return RTSerialPortChgStatusLines(pThis->hSerialPort, fClear, fSet);
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgBrk}
- */
-static DECLCALLBACK(int) drvHostSerialChgBrk(PPDMISERIALCONNECTOR pInterface, bool fBrk)
-{
- PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
-
- return RTSerialPortChgBreakCondition(pThis->hSerialPort, fBrk);
-}
-
-
-/**
- * @interface_method_impl{PDMISERIALCONNECTOR,pfnQueryStsLines}
- */
-static DECLCALLBACK(int) drvHostSerialQueryStsLines(PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)
-{
- PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector);
-
- return RTSerialPortQueryStatusLines(pThis->hSerialPort, pfStsLines);
-}
-
-
-/* -=-=-=-=- I/O thread -=-=-=-=- */
-
-/**
- * I/O thread loop.
- *
- * @returns VINF_SUCCESS.
- * @param pDrvIns PDM driver instance data.
- * @param pThread The PDM thread data.
- */
-static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
-
- if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
- return VINF_SUCCESS;
-
- while (pThread->enmState == PDMTHREADSTATE_RUNNING)
- {
- uint32_t fEvtFlags = RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED | RTSERIALPORT_EVT_F_BREAK_DETECTED;
-
- if (!pThis->fAvailWrInt)
- pThis->fAvailWrInt = ASMAtomicXchgBool(&pThis->fAvailWrExt, false);
-
- /* Wait until there is room again if there is anyting to send. */
- if ( pThis->fAvailWrInt
- || pThis->cbTxUsed)
- fEvtFlags |= RTSERIALPORT_EVT_F_DATA_TX;
-
- /* Try to receive more if there is still room. */
- if (drvHostSerialReadBufGetWrite(pThis, NULL) > 0)
- fEvtFlags |= RTSERIALPORT_EVT_F_DATA_RX;
-
- uint32_t fEvtsRecv = 0;
- int rc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv, RT_INDEFINITE_WAIT);
- if (RT_SUCCESS(rc))
- {
- if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_TX)
- {
- if (pThis->fAvailWrInt)
- {
- /* Stuff as much data into the TX buffer as we can. */
- size_t cbToFetch = RT_ELEMENTS(pThis->abTxBuf) - pThis->cbTxUsed;
- size_t cbFetched = 0;
- rc = pThis->pDrvSerialPort->pfnReadWr(pThis->pDrvSerialPort, &pThis->abTxBuf[pThis->cbTxUsed], cbToFetch,
- &cbFetched);
- AssertRC(rc);
-
- if (cbFetched > 0)
- pThis->cbTxUsed += cbFetched;
- else
- {
- /* There is no data available anymore. */
- pThis->fAvailWrInt = false;
- }
- }
-
- if (pThis->cbTxUsed)
- {
- size_t cbProcessed = 0;
- rc = RTSerialPortWriteNB(pThis->hSerialPort, &pThis->abTxBuf[0], pThis->cbTxUsed, &cbProcessed);
- if (RT_SUCCESS(rc))
- {
- pThis->cbTxUsed -= cbProcessed;
- if (pThis->cbTxUsed)
- {
- /* Move the data in the TX buffer to the front to fill the end again. */
- memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed);
- }
- else
- pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort);
- STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbProcessed);
- }
- else
- {
- LogRelMax(10, ("HostSerial#%d: Sending data failed even though the serial port is marked as writeable (rc=%Rrc)\n",
- pThis->pDrvIns->iInstance, rc));
- break;
- }
- }
- }
-
- if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_RX)
- {
- void *pvDst = NULL;
- size_t cbToRead = drvHostSerialReadBufGetWrite(pThis, &pvDst);
- size_t cbRead = 0;
- rc = RTSerialPortReadNB(pThis->hSerialPort, pvDst, cbToRead, &cbRead);
- if (RT_SUCCESS(rc))
- {
- drvHostSerialReadBufWriteAdv(pThis, cbRead);
- /* Notify the device/driver above. */
- rc = pThis->pDrvSerialPort->pfnDataAvailRdrNotify(pThis->pDrvSerialPort, cbRead);
- AssertRC(rc);
- }
- else
- LogRelMax(10, ("HostSerial#%d: Reading data failed even though the serial port is marked as readable (rc=%Rrc)\n",
- pThis->pDrvIns->iInstance, rc));
- }
-
- if (fEvtsRecv & RTSERIALPORT_EVT_F_BREAK_DETECTED)
- pThis->pDrvSerialPort->pfnNotifyBrk(pThis->pDrvSerialPort);
-
- if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
- {
- /* The status lines have changed. Notify the device. */
- uint32_t fStsLines = 0;
- rc = RTSerialPortQueryStatusLines(pThis->hSerialPort, &fStsLines);
- if (RT_SUCCESS(rc))
- {
- uint32_t fPdmStsLines = 0;
-
- if (fStsLines & RTSERIALPORT_STS_LINE_DCD)
- fPdmStsLines |= PDMISERIALPORT_STS_LINE_DCD;
- if (fStsLines & RTSERIALPORT_STS_LINE_RI)
- fPdmStsLines |= PDMISERIALPORT_STS_LINE_RI;
- if (fStsLines & RTSERIALPORT_STS_LINE_DSR)
- fPdmStsLines |= PDMISERIALPORT_STS_LINE_DSR;
- if (fStsLines & RTSERIALPORT_STS_LINE_CTS)
- fPdmStsLines |= PDMISERIALPORT_STS_LINE_CTS;
-
- rc = pThis->pDrvSerialPort->pfnNotifyStsLinesChanged(pThis->pDrvSerialPort, fPdmStsLines);
- if (RT_FAILURE(rc))
- {
- /* Notifying device failed, continue but log it */
- LogRelMax(10, ("HostSerial#%d: Notifying device about changed status lines failed with error %Rrc; continuing.\n",
- pDrvIns->iInstance, rc));
- }
- }
- else
- LogRelMax(10, ("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc));
- }
-
- if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED)
- LogRel(("HostSerial#%d: Status line monitoring failed at a lower level and is disabled\n", pDrvIns->iInstance));
- }
- else if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
- {
- /* Getting interrupted or running into a timeout are no error conditions. */
- rc = VINF_SUCCESS;
- }
- }
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Unblock the send thread so it can respond to a state change.
- *
- * @returns a VBox status code.
- * @param pDrvIns The driver instance.
- * @param pThread The send thread.
- */
-static DECLCALLBACK(int) drvHostSerialWakeupIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
-{
- RT_NOREF(pThread);
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
-
- return RTSerialPortEvtPollInterrupt(pThis->hSerialPort);
-}
-
-
-/* -=-=-=-=- driver interface -=-=-=-=- */
-
-/**
- * Destruct a char driver instance.
- *
- * Most VM resources are freed by the VM. This callback is provided so that
- * any non-VM resources can be freed correctly.
- *
- * @param pDrvIns The driver instance data.
- */
-static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
-{
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
- LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
-
- if (pThis->hSerialPort != NIL_RTSERIALPORT)
- {
- RTSerialPortClose(pThis->hSerialPort);
- pThis->hSerialPort = NIL_RTSERIALPORT;
- }
-
- if (pThis->pszDevicePath)
- {
- MMR3HeapFree(pThis->pszDevicePath);
- pThis->pszDevicePath = NULL;
- }
-}
-
-
-/**
- * Construct a char driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF1(fFlags);
- PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL);
- LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
-
- /*
- * Init basic data members and interfaces.
- */
- pThis->pDrvIns = pDrvIns;
- pThis->hSerialPort = NIL_RTSERIALPORT;
- pThis->fAvailWrExt = false;
- pThis->fAvailWrInt = false;
- pThis->cbTxUsed = 0;
- pThis->offWrite = 0;
- pThis->offRead = 0;
- pThis->cbReadBuf = 0;
- /* IBase. */
- pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
- /* ISerialConnector. */
- pThis->ISerialConnector.pfnDataAvailWrNotify = drvHostSerialDataAvailWrNotify;
- pThis->ISerialConnector.pfnReadRdr = drvHostSerialReadRdr;
- pThis->ISerialConnector.pfnChgParams = drvHostSerialChgParams;
- pThis->ISerialConnector.pfnChgModemLines = drvHostSerialChgModemLines;
- pThis->ISerialConnector.pfnChgBrk = drvHostSerialChgBrk;
- pThis->ISerialConnector.pfnQueryStsLines = drvHostSerialQueryStsLines;
-
- /*
- * Query configuration.
- */
- /* Device */
- int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath);
- if (RT_FAILURE(rc))
- {
- AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc));
- return rc;
- }
-
- /*
- * Open the device
- */
- uint32_t fOpenFlags = RTSERIALPORT_OPEN_F_READ
- | RTSERIALPORT_OPEN_F_WRITE
- | RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING
- | RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION;
- rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
- if (rc == VERR_NOT_SUPPORTED)
- {
- /*
- * For certain devices (or pseudo terminals) status line monitoring does not work
- * so try again without it.
- */
- fOpenFlags &= ~RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING;
- rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags);
- }
-
- if (RT_FAILURE(rc))
- {
- AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pThis->pszDevicePath, rc));
- switch (rc)
- {
- case VERR_ACCESS_DENIED:
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
-#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
- N_("Cannot open host device '%s' for read/write access. Check the permissions "
- "of that device ('/bin/ls -l %s'): Most probably you need to be member "
- "of the device group. Make sure that you logout/login after changing "
- "the group settings of the current user"),
-#else
- N_("Cannot open host device '%s' for read/write access. Check the permissions "
- "of that device"),
-#endif
- pThis->pszDevicePath, pThis->pszDevicePath);
- default:
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
- N_("Failed to open host device '%s'"),
- pThis->pszDevicePath);
- }
- }
-
- /*
- * Get the ISerialPort interface of the above driver/device.
- */
- pThis->pDrvSerialPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISERIALPORT);
- if (!pThis->pDrvSerialPort)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no serial port interface above"), pDrvIns->iInstance);
-
- /*
- * Create the I/O thread.
- */
- rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pIoThrd, pThis, drvHostSerialIoThread, drvHostSerialWakeupIoThread, 0, RTTHREADTYPE_IO, "SerIo");
- if (RT_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create I/O thread"), pDrvIns->iInstance);
-
- /*
- * Register release statistics.
- */
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
- "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
- "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostSerial =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "Host Serial",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Host serial driver.",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_CHAR,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTSERIAL),
- /* pfnConstruct */
- drvHostSerialConstruct,
- /* pfnDestruct */
- drvHostSerialDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
diff --git a/src/VBox/Devices/testcase/Makefile.kmk b/src/VBox/Devices/testcase/Makefile.kmk
index b5c38231cd8..4f51b0a5197 100644
--- a/src/VBox/Devices/testcase/Makefile.kmk
+++ b/src/VBox/Devices/testcase/Makefile.kmk
@@ -48,7 +48,6 @@ VBOX_DEVICES_TESTS_FEATURES = \
$(if $(VBOX_WITH_VMSVGA),VBOX_WITH_VMSVGA,) \
$(if $(VBOX_WITH_WDDM),VBOX_WITH_WDDM,) \
$(if $(VBOX_WITH_XHCI_IMPL),VBOX_WITH_XHCI_IMPL,) \
- $(if $(VBOX_WITH_NEW_SERIAL),VBOX_WITH_NEW_SERIAL,) \
$(VBOX_AUDIO_DEFS)
#
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
index f809a369fdb..ad93e8e1485 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
@@ -109,12 +109,9 @@
#undef LOG_GROUP
#include "../Parallel/DevParallel.cpp"
#undef LOG_GROUP
-#ifndef VBOX_WITH_NEW_SERIAL
-# include "../Serial/DevSerial.cpp"
-#else
-# include "../Serial/DevSerialNew.cpp"
-# include "../Serial/DevOxPcie958.cpp"
-#endif
+#include "../Serial/DevSerial.cpp"
+#undef LOG_GROUP
+#include "../Serial/DevOxPcie958.cpp"
#ifdef VBOX_WITH_AHCI
# undef LOG_GROUP
# include "../Storage/DevAHCI.cpp"
@@ -397,12 +394,8 @@ int main()
CHECK_MEMBER_ALIGNMENT(PCNETSTATE, StatMMIOReadRZ, 8);
#endif
CHECK_MEMBER_ALIGNMENT(PITSTATE, StatPITIrq, 8);
-#ifndef VBOX_WITH_NEW_SERIAL
- CHECK_MEMBER_ALIGNMENT(SerialState, CritSect, 8);
-#else
CHECK_MEMBER_ALIGNMENT(DEVSERIAL, UartCore, 8);
CHECK_MEMBER_ALIGNMENT(UARTCORE, CritSect, 8);
-#endif
#ifdef VBOX_WITH_VMSVGA
CHECK_SIZE(VMSVGAState, RT_ALIGN_Z(sizeof(VMSVGAState), 8));
CHECK_MEMBER_ALIGNMENT(VGASTATE, svga, 8);
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index 832e090fe84..f9086b0663f 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -108,13 +108,11 @@
#undef LOG_GROUP
#include "../Parallel/DevParallel.cpp"
#undef LOG_GROUP
-#ifndef VBOX_WITH_NEW_SERIAL
-# include "../Serial/DevSerial.cpp"
-#else
-# include "../Serial/DevSerialNew.cpp"
-# include "../Serial/DevOxPcie958.cpp"
-# include "../Serial/UartCore.h"
-#endif
+#include "../Serial/DevSerial.cpp"
+#undef LOG_GROUP
+#include "../Serial/DevOxPcie958.cpp"
+#undef LOG_GROUP
+#include "../Serial/UartCore.h"
#ifdef VBOX_WITH_AHCI
# undef LOG_GROUP
# include "../Storage/DevAHCI.cpp"
@@ -1279,45 +1277,6 @@ int main()
GEN_CHECK_OFF(PARALLELPORT, act_fifo_pos_read);
#endif
-#ifndef VBOX_WITH_NEW_SERIAL
- /* Serial/DevSerial.cpp */
- GEN_CHECK_SIZE(SerialState);
- GEN_CHECK_OFF(SerialState, CritSect);
- GEN_CHECK_OFF(SerialState, pDevInsR3);
- GEN_CHECK_OFF(SerialState, pDevInsR0);
- GEN_CHECK_OFF(SerialState, pDevInsRC);
- GEN_CHECK_OFF(SerialState, IBase);
- GEN_CHECK_OFF(SerialState, ICharPort);
- GEN_CHECK_OFF(SerialState, pDrvBase);
- GEN_CHECK_OFF(SerialState, pDrvChar);
- GEN_CHECK_OFF(SerialState, ReceiveSem);
- GEN_CHECK_OFF(SerialState, base);
- GEN_CHECK_OFF(SerialState, divider);
- GEN_CHECK_OFF(SerialState, recv_fifo);
- GEN_CHECK_OFF(SerialState, xmit_fifo);
- GEN_CHECK_OFF(SerialState, rbr);
- GEN_CHECK_OFF(SerialState, thr);
- GEN_CHECK_OFF(SerialState, tsr);
- GEN_CHECK_OFF(SerialState, ier);
- GEN_CHECK_OFF(SerialState, iir);
- GEN_CHECK_OFF(SerialState, lcr);
- GEN_CHECK_OFF(SerialState, mcr);
- GEN_CHECK_OFF(SerialState, lsr);
- GEN_CHECK_OFF(SerialState, msr);
- GEN_CHECK_OFF(SerialState, scr);
- GEN_CHECK_OFF(SerialState, fcr);
- GEN_CHECK_OFF(SerialState, fcr_vmstate);
- GEN_CHECK_OFF(SerialState, thr_ipending);
- GEN_CHECK_OFF(SerialState, timeout_ipending);
- GEN_CHECK_OFF(SerialState, irq);
- GEN_CHECK_OFF(SerialState, last_break_enable);
- GEN_CHECK_OFF(SerialState, tsr_retry);
- GEN_CHECK_OFF(SerialState, msr_changed);
- GEN_CHECK_OFF(SerialState, fGCEnabled);
- GEN_CHECK_OFF(SerialState, fR0Enabled);
- GEN_CHECK_OFF(SerialState, fYieldOnLSRRead);
- GEN_CHECK_OFF(SerialState, char_transmit_time);
-#else
/* Serial/UartCore.cpp */
GEN_CHECK_SIZE(UARTCORE);
GEN_CHECK_OFF(UARTCORE, CritSect);
@@ -1355,7 +1314,7 @@ int main()
GEN_CHECK_OFF(UARTCORE, cSymbolXferTicks);
GEN_CHECK_OFF(UARTCORE, cbAvailRdr);
- /* Serial/DevSerialNew.cpp */
+ /* Serial/DevSerial.cpp */
GEN_CHECK_SIZE(DEVSERIAL);
GEN_CHECK_OFF(DEVSERIAL, pDevInsR3);
GEN_CHECK_OFF(DEVSERIAL, pDevInsR0);
@@ -1381,7 +1340,6 @@ int main()
GEN_CHECK_OFF(DEVOX958, GCPhysMMIO);
GEN_CHECK_OFF(DEVOX958, aUarts);
GEN_CHECK_OFF(DEVOX958, aUarts[OX958_UARTS_MAX - 1]);
-#endif
#ifdef VBOX_WITH_AHCI
/* Storage/DevAHCI.cpp */