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