DevSerial.cpp revision 30adc6dd25ed9fef4d800a6d9f1ab7e765b4c340
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/** @file
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * VBox serial device:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Serial communication port driver
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Copyright (C) 2006-2007 innotek GmbH
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * available from http://www.virtualbox.org. This file is free software;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * General Public License (GPL) as published by the Free Software
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * This code is based on:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * QEMU 16450 UART emulation
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Copyright (c) 2003-2004 Fabrice Bellard
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * of this software and associated documentation files (the "Software"), to deal
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * in the Software without restriction, including without limitation the rights
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * copies of the Software, and to permit persons to whom the Software is
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * furnished to do so, subject to the following conditions:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * The above copyright notice and this permission notice shall be included in
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * all copies or substantial portions of the Software.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * THE SOFTWARE.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/*******************************************************************************
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync* Header Files *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync*******************************************************************************/
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define LOG_GROUP LOG_GROUP_DEV_SERIAL
ecb98c0e709a5cebd8877fb39f61a821804024bcvboxsync#include <VBox/pdmdev.h>
ecb98c0e709a5cebd8877fb39f61a821804024bcvboxsync#include <iprt/assert.h>
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#include <iprt/uuid.h>
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#include <iprt/string.h>
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#include <iprt/semaphore.h>
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#include <iprt/critsect.h>
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#include "Builtins.h"
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef VBOX_SERIAL_PCI
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#include <VBox/pci.h>
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif /* VBOX_SERIAL_PCI */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define SERIAL_SAVED_STATE_VERSION 3
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IIR_MSI 0x00 /* Modem status interrupt */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * These are the definitions for the Modem Control Register
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MCR_OUT2 0x08 /* Out2 complement */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MCR_OUT1 0x04 /* Out1 complement */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MCR_RTS 0x02 /* RTS complement */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MCR_DTR 0x01 /* DTR complement */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * These are the definitions for the Modem Status Register
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_RI 0x40 /* Ring Indicator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_DSR 0x20 /* Data Set Ready */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_CTS 0x10 /* Clear to Send */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_DDCD 0x08 /* Delta DCD */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_DDSR 0x02 /* Delta DSR */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_DCTS 0x01 /* Delta CTS */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_TEMT 0x40 /* Transmitter empty */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_BI 0x10 /* Break interrupt indicator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_FE 0x08 /* Frame error indicator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_PE 0x04 /* Parity error indicator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_OE 0x02 /* Overrun error indicator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define UART_LSR_DR 0x01 /* Receiver data ready */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstruct SerialState
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** Access critical section. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMCRITSECT CritSect;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** Pointer to the device instance. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync R3PTRTYPE(PPDMDEVINS) pDevInsHC;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** Pointer to the device instance. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync GCPTRTYPE(PPDMDEVINS) pDevInsGC;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#if HC_ARCH_BITS == 64 && GC_ARCH_BITS != 64
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync RTGCPTR Alignment0;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** The base interface. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMIBASE IBase;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** The character port interface. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMICHARPORT ICharPort;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** Pointer to the attached base driver. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync R3PTRTYPE(PPDMIBASE) pDrvBase;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /** Pointer to the attached character driver. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync R3PTRTYPE(PPDMICHAR) pDrvChar;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint16_t divider;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint16_t auAlignment[3];
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t rbr; /* receive register */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t ier;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t iir; /* read only */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t lcr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t mcr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t lsr; /* read only */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t msr; /* read only */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t scr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* NOTE: this hidden state is necessary for tx irq generation as
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync it can be reset while reading iir */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int thr_ipending;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int irq;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync bool msr_changed;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync bool fGCEnabled;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync bool fR0Enabled;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync bool afAlignment[5];
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync RTSEMEVENT ReceiveSem;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int last_break_enable;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint32_t base;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef VBOX_SERIAL_PCI
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PCIDEVICE dev;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif /* VBOX_SERIAL_PCI */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync};
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifndef VBOX_DEVICE_STRUCT_TESTCASE
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef VBOX_SERIAL_PCI
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif /* VBOX_SERIAL_PCI */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync__BEGIN_DECLS
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncPDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncPDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync__END_DECLS
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
6a0359b8230a1b91fe49967c124a75191c3dfbf9vboxsync#ifdef IN_RING3
9f22c692723a5d3cb78b91896c48cf681c4fb608vboxsyncstatic void serial_update_irq(SerialState *s)
83d61602c6968041692aa7203ee51c4085c7e460vboxsync{
83d61602c6968041692aa7203ee51c4085c7e460vboxsync if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
6a0359b8230a1b91fe49967c124a75191c3dfbf9vboxsync s->iir = UART_IIR_RDI;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
4f9276b4c85a4617d08094484cc1d983791bbb16vboxsync s->iir = UART_IIR_THRI;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else if (s->msr_changed && (s->ier & UART_IER_RLSI)) {
a9d98aa17ecb241bc2c79b67dc044f0af2eb7448vboxsync s->iir = UART_IIR_RLSI;
83d61602c6968041692aa7203ee51c4085c7e460vboxsync } else {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->iir = UART_IIR_NO_INT;
1e0e13b23ace43d2fe93d45953b123f63b7e547cvboxsync }
1e0e13b23ace43d2fe93d45953b123f63b7e547cvboxsync if (s->iir != UART_IIR_NO_INT) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Log(("serial_update_irq %d 1\n", s->irq));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef VBOX_SERIAL_PCI
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMDevHlpPCISetIrqNoWait(CTXSUFF(s->pDevIns), 0, 1);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#else /* !VBOX_SERIAL_PCI */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 1);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync#endif /* !VBOX_SERIAL_PCI */
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync } else {
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync Log(("serial_update_irq %d 0\n", s->irq));
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync#ifdef VBOX_SERIAL_PCI
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync PDMDevHlpPCISetIrqNoWait(CTXSUFF(s->pDevIns), 0, 0);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync#else /* !VBOX_SERIAL_PCI */
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 0);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync#endif /* !VBOX_SERIAL_PCI */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
6a0359b8230a1b91fe49967c124a75191c3dfbf9vboxsyncstatic void serial_update_parameters(SerialState *s)
6a0359b8230a1b91fe49967c124a75191c3dfbf9vboxsync{
6a0359b8230a1b91fe49967c124a75191c3dfbf9vboxsync int speed, parity, data_bits, stop_bits;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr & 0x08) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr & 0x10)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync parity = 'E';
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync else
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync parity = 'O';
9f22c692723a5d3cb78b91896c48cf681c4fb608vboxsync } else {
9f22c692723a5d3cb78b91896c48cf681c4fb608vboxsync parity = 'N';
9f22c692723a5d3cb78b91896c48cf681c4fb608vboxsync }
83d61602c6968041692aa7203ee51c4085c7e460vboxsync if (s->lcr & 0x04)
83d61602c6968041692aa7203ee51c4085c7e460vboxsync stop_bits = 2;
83d61602c6968041692aa7203ee51c4085c7e460vboxsync else
83d61602c6968041692aa7203ee51c4085c7e460vboxsync stop_bits = 1;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync data_bits = (s->lcr & 0x03) + 5;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->divider == 0)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync speed = 115200 / s->divider;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (RT_LIKELY(s->pDrvChar))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif
a9d98aa17ecb241bc2c79b67dc044f0af2eb7448vboxsync
a9d98aa17ecb241bc2c79b67dc044f0af2eb7448vboxsyncstatic int serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
a9d98aa17ecb241bc2c79b67dc044f0af2eb7448vboxsync{
83d61602c6968041692aa7203ee51c4085c7e460vboxsync SerialState *s = (SerialState *)opaque;
83d61602c6968041692aa7203ee51c4085c7e460vboxsync unsigned char ch;
83d61602c6968041692aa7203ee51c4085c7e460vboxsync
1e0e13b23ace43d2fe93d45953b123f63b7e547cvboxsync addr &= 7;
1e0e13b23ace43d2fe93d45953b123f63b7e547cvboxsync LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));
1e0e13b23ace43d2fe93d45953b123f63b7e547cvboxsync
1e0e13b23ace43d2fe93d45953b123f63b7e547cvboxsync#ifndef IN_RING3
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync NOREF(ch);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync NOREF(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return VINF_IOM_HC_IOPORT_WRITE;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#else
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync switch(addr) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync default:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 0:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr & UART_LCR_DLAB) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->divider = (s->divider & 0xff00) | val;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_parameters(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->thr_ipending = 0;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->lsr &= ~UART_LSR_THRE;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_irq(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ch = val;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (RT_LIKELY(s->pDrvChar))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Log(("serial_io_port_write: write 0x%X\n", ch));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertRC(rc);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->thr_ipending = 1;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->lsr |= UART_LSR_THRE;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->lsr |= UART_LSR_TEMT;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_irq(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 1:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr & UART_LCR_DLAB) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->divider = (s->divider & 0x00ff) | (val << 8);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_parameters(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->ier = val & 0x0f;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lsr & UART_LSR_THRE) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->thr_ipending = 1;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_irq(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 2:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 3:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int break_enable;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr != val)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->lcr = val;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_parameters(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break_enable = (val >> 6) & 1;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (break_enable != s->last_break_enable) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->last_break_enable = break_enable;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 4:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->mcr = val & 0x1f;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (RT_LIKELY(s->pDrvChar))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar, !!(s->mcr & UART_MCR_RTS), !!(s->mcr & UART_MCR_DTR));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertRC(rc);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 5:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 6:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 7:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->scr = val;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return VINF_SUCCESS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic uint32_t serial_ioport_read(void *opaque, uint32_t addr, int *pRC)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *s = (SerialState *)opaque;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint32_t ret = ~0U;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *pRC = VINF_SUCCESS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync addr &= 7;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync switch(addr) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync default:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 0:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr & UART_LCR_DLAB) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->divider & 0xff;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifndef IN_RING3
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *pRC = VINF_IOM_HC_IOPORT_READ;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#else
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Log(("serial_io_port_read: read 0x%X\n", s->rbr));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->rbr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_irq(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int rc = RTSemEventSignal(s->ReceiveSem);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertRC(rc);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 1:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->lcr & UART_LCR_DLAB) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = (s->divider >> 8) & 0xff;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->ier;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 2:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifndef IN_RING3
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *pRC = VINF_IOM_HC_IOPORT_READ;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#else
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->iir;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* reset THR pending bit */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if ((ret & 0x7) == UART_IIR_THRI)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->thr_ipending = 0;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* reset msr changed bit */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->msr_changed = false;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_irq(s);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 3:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->lcr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 4:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->mcr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 5:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->lsr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 6:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (s->mcr & UART_MCR_LOOP) {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* in loopback, the modem output pins are connected to the
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync inputs */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = (s->mcr & 0x0c) << 4;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret |= (s->mcr & 0x02) << 3;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret |= (s->mcr & 0x01) << 5;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync } else {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->msr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* Reset delta bits. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync s->msr &= ~UART_MSR_ANY_DELTA;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case 7:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync ret = s->scr;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync break;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return ret;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef IN_RING3
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMICHARPORT_2_SERIALSTATE(pInterface);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Assert(*pcbRead != 0);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (pData->lsr & UART_LSR_DR)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* If a character is still in the read queue, then wait for it to be emptied. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMCritSectLeave(&pData->CritSect);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = RTSemEventWait(pData->ReceiveSem, 250);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (VBOX_FAILURE(rc))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (!(pData->lsr & UART_LSR_DR))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->rbr = *(const char *)pvBuf;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->lsr |= UART_LSR_DR;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_update_irq(pData);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *pcbRead = 1;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = VINF_SUCCESS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync else
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = VERR_TIMEOUT;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMCritSectLeave(&pData->CritSect);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMICHARPORT_2_SERIALSTATE(pInterface);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t newMsr = 0;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* Set new states. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (newStatusLines & PDM_ICHAR_STATUS_LINES_DCD)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_DCD;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (newStatusLines & PDM_ICHAR_STATUS_LINES_RI)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_RI;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (newStatusLines & PDM_ICHAR_STATUS_LINES_DSR)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_DSR;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (newStatusLines & PDM_ICHAR_STATUS_LINES_CTS)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_CTS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* Compare the old and the new states and set the delta bits accordingly. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if ((newMsr & UART_MSR_DCD) != (pData->msr & UART_MSR_DCD))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_DDCD;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if ((newMsr & UART_MSR_RI) == 1 && (pData->msr & UART_MSR_RI) == 0)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_TERI;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if ((newMsr & UART_MSR_DSR) != (pData->msr & UART_MSR_DSR))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_DDSR;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if ((newMsr & UART_MSR_CTS) != (pData->msr & UART_MSR_CTS))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync newMsr |= UART_MSR_DCTS;
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync pData->msr = newMsr;
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync pData->msr_changed = true;
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync serial_update_irq(pData);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync PDMCritSectLeave(&pData->CritSect);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync return VINF_SUCCESS;
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync}
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync#endif /* IN_RING3 */
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync/**
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * Port I/O Handler for OUT operations.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync *
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * @returns VBox status code.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync *
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * @param pDevIns The device instance.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * @param pvUser User argument.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * @param Port Port number used for the IN operation.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * @param u32 The value to output.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync * @param cb The value size in bytes.
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync */
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsyncPDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync RTIOPORT Port, uint32_t u32, unsigned cb)
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync{
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync int rc = VINF_SUCCESS;
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync if (cb == 1)
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync {
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync if (rc == VINF_SUCCESS)
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync {
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync rc = serial_ioport_write (pData, Port, u32);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync PDMCritSectLeave(&pData->CritSect);
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync }
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync }
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync else
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync return rc;
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync}
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync/**
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * Port I/O Handler for IN operations.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync *
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * @returns VBox status code.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync *
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * @param pDevIns The device instance.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * @param pvUser User argument.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * @param Port Port number used for the IN operation.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * @param u32 The value to output.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync * @param cb The value size in bytes.
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync */
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsyncPDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync RTIOPORT Port, uint32_t *pu32, unsigned cb)
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync{
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync int rc = VINF_SUCCESS;
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync if (cb == 1)
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync {
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync if (rc == VINF_SUCCESS)
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync {
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync *pu32 = serial_ioport_read (pData, Port, &rc);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
34c7651e294c98d15cac0b35e5a585404c0d26aavboxsync PDMCritSectLeave(&pData->CritSect);
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync }
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync }
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync else
9d7b020d79101e5c23c1f58a0ce5fa49488ccf73vboxsync rc = VERR_IOM_IOPORT_UNUSED;
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync return rc;
6ea079037b825359aab1ba56bb4b9e202ecea648vboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef IN_RING3
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/**
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Saves a state of the serial port device.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @returns VBox status code.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param pDevIns The device instance.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param pSSMHandle The handle to save the state to.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PSSMHANDLE pSSMHandle)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU16(pSSMHandle, pData->divider);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->rbr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->ier);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->lcr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->mcr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->lsr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->msr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU8(pSSMHandle, pData->scr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutS32(pSSMHandle, pData->thr_ipending);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutS32(pSSMHandle, pData->irq);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutS32(pSSMHandle, pData->last_break_enable);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutU32(pSSMHandle, pData->base);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3PutBool(pSSMHandle, pData->msr_changed);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/**
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Loads a saved serial port device state.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @returns VBox status code.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param pDevIns The device instance.
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync * @param pSSMHandle The handle to the saved state.
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync * @param u32Version The data unit version number.
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync */
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsyncstatic DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PSSMHANDLE pSSMHandle,
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync uint32_t u32Version)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync int rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint32_t u32;
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync if (u32Version != SERIAL_SAVED_STATE_VERSION)
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync {
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync AssertMsgFailed(("u32Version=%d\n", u32Version));
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync }
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU16(pSSMHandle, &pData->divider);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->rbr);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->ier);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->lcr);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->mcr);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->lsr);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->msr);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU8(pSSMHandle, &pData->scr);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3GetS32(pSSMHandle, &pData->thr_ipending);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetS32(pSSMHandle, &pData->irq);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetS32(pSSMHandle, &pData->last_break_enable);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync SSMR3GetU32(pSSMHandle, &pData->base);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SSMR3GetBool(pSSMHandle, &pData->msr_changed);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync rc = SSMR3GetU32(pSSMHandle, &u32);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync if (VBOX_FAILURE(rc))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync if (u32 != ~0U)
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync {
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync AssertMsgFailed(("u32=%#x expected ~0\n", u32));
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync }
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync /* Be careful with pointers in the structure; they are not preserved
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * in the saved state. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync if (pData->lsr & UART_LSR_DR)
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync {
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync int rc = RTSemEventSignal(pData->ReceiveSem);
90ce7af4052f25f4a94d18c0ef86181971396cd3vboxsync AssertRC(rc);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->pDevInsHC = pDevIns;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return VINF_SUCCESS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/**
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @copydoc FNPDMDEVRELOCATE
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#ifdef VBOX_SERIAL_PCI
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PCIDEV_2_SERIALSTATE(pPciDev);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int rc = VINF_SUCCESS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Assert(enmType == PCI_ADDRESS_SPACE_IO);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Assert(iRegion == 0);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Assert(cb == 8);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->base = (RTIOPORT)GCPhysAddress;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync LogRel(("Serial#%d: mapping I/O at %#06x\n", pData->pDevIns->iInstance, pData->base));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Register our port IO handlers.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pData,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertRC(rc);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync#endif /* VBOX_SERIAL_PCI */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/** @copyfrom PIBASE::pfnqueryInterface */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMIBASE_2_SERIALSTATE(pInterface);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync switch (enmInterface)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case PDMINTERFACE_BASE:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return &pData->IBase;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync case PDMINTERFACE_CHAR_PORT:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return &pData->ICharPort;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync default:
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return NULL;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
ecb98c0e709a5cebd8877fb39f61a821804024bcvboxsync/**
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Destruct a device instance.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * resources can be freed correctly.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @returns VBox status.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param pDevIns The device instance data.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync RTSemEventDestroy(pData->ReceiveSem);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->ReceiveSem = NIL_RTSEMEVENT;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PDMR3CritSectDelete(&pData->CritSect);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return VINF_SUCCESS;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync}
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync/**
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Construct a device instance for a VM.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync *
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @returns VBox status.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param pDevIns The device instance data.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * If the registration structure is needed, pDevIns->pDevReg points to it.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param iInstance Instance number. Use this to figure out which registers and such to use.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * The device number is also found in pDevIns->iInstance, but since it's
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * likely to be freqently used PDM passes it as parameter.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * of the device instance. It's also found in pDevIns->pCfgHandle, but like
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * iInstance it's expected to be used a bit in this function.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsyncstatic DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int iInstance,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync PCFGMNODE pCfgHandle)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync{
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync int rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync SerialState *pData = PDMINS2DATA(pDevIns, SerialState*);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint16_t io_base;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync uint8_t irq_lvl;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync Assert(iInstance < 4);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->pDevInsHC = pDevIns;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Validate configuration.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0IOBase\0"))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
728b52f802ac19865bd4aa8e9ade8f506a9e6c10vboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
728b52f802ac19865bd4aa8e9ade8f506a9e6c10vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->fGCEnabled = true;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync else if (VBOX_FAILURE(rc))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync N_("Configuration error: Failed to get the \"GCEnabled\" value"));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->fR0Enabled = true;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync else if (VBOX_FAILURE(rc))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync N_("Configuration error: Failed to get the \"R0Enabled\" value"));
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* IBase */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->IBase.pfnQueryInterface = serialQueryInterface;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* ICharPort */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->ICharPort.pfnNotifyRead = serialNotifyRead;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync pData->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = RTSemEventCreate(&pData->ReceiveSem);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync AssertRC(rc);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /*
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * Initialize critical section.
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync * This must of course be done before attaching drivers or anything else which can call us back..
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync char szName[24];
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync RTStrPrintf(szName, sizeof(szName), "Serial#%d", iInstance);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (VBOX_FAILURE(rc))
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync return rc;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync {
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync /* Provide sensible defaults. */
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync if (iInstance == 0)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync irq_lvl = 4;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync else if (iInstance == 1)
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync irq_lvl = 3;
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync }
41d680dd6eb0287afc200adc5b0d61b07a32b72dvboxsync else if (VBOX_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"IRQ\" value"));
rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
if (iInstance == 0)
io_base = 0x3f8;
else if (iInstance == 1)
io_base = 0x2f8;
}
else if (VBOX_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"IOBase\" value"));
Log(("serialConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
pData->irq = irq_lvl;
pData->lsr = UART_LSR_TEMT | UART_LSR_THRE;
pData->iir = UART_IIR_NO_INT;
pData->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
#ifdef VBOX_SERIAL_PCI
pData->base = -1;
pData->dev.config[0x00] = 0xee; /* Vendor: ??? */
pData->dev.config[0x01] = 0x80;
pData->dev.config[0x02] = 0x01; /* Device: ??? */
pData->dev.config[0x03] = 0x01;
pData->dev.config[0x04] = PCI_COMMAND_IOACCESS;
pData->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
pData->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
pData->dev.config[0x0b] = 0x07; /* Class: Communication controller */
pData->dev.config[0x0e] = 0x00; /* Header type: standard */
pData->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
pData->dev.config[0x3d] = 1; /* interrupt pin 0 */
rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
if (VBOX_FAILURE(rc))
return rc;
/*
* Register the PCI I/O ports.
*/
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
if (VBOX_FAILURE(rc))
return rc;
#else /* !VBOX_SERIAL_PCI */
pData->base = io_base;
rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
serialIOPortWrite, serialIOPortRead,
NULL, NULL, "SERIAL");
if (VBOX_FAILURE (rc))
return rc;
if (pData->fGCEnabled)
rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
"serialIOPortRead", NULL, NULL, "Serial");
if (pData->fR0Enabled)
rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
"serialIOPortRead", NULL, NULL, "Serial");
#endif /* !VBOX_SERIAL_PCI */
/* Attach the char driver and get the interfaces. For now no run-time
* changes are supported. */
rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Serial Char");
if (VBOX_SUCCESS(rc))
{
pData->pDrvChar = (PDMICHAR *)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_CHAR);
if (!pData->pDrvChar)
{
AssertMsgFailed(("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)
{
pData->pDrvBase = NULL;
pData->pDrvChar = NULL;
LogRel(("Serial%d: no unit\n", iInstance));
}
else
{
AssertMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Vrc\n", iInstance, rc));
/* Don't call VMSetError here as we assume that the driver already set an appropriate error */
return rc;
}
rc = PDMDevHlpSSMRegister (
pDevIns, /* pDevIns */
pDevIns->pDevReg->szDeviceName, /* pszName */
iInstance, /* u32Instance */
SERIAL_SAVED_STATE_VERSION, /* u32Version */
sizeof (*pData), /* cbGuess */
NULL, /* pfnSavePrep */
serialSaveExec, /* pfnSaveExec */
NULL, /* pfnSaveDone */
NULL, /* pfnLoadPrep */
serialLoadExec, /* pfnLoadExec */
NULL /* pfnLoadDone */
);
if (VBOX_FAILURE(rc))
return rc;
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceSerialPort =
{
/* u32Version */
PDM_DEVREG_VERSION,
/* szDeviceName */
"serial",
/* szGCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"Serial Communication Port",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
/* fClass */
PDM_DEVREG_CLASS_SERIAL,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(SerialState),
/* pfnConstruct */
serialConstruct,
/* pfnDestruct */
serialDestruct,
/* pfnRelocate */
serialRelocate,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */