summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/src-server/SerialPortImpl.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Main/src-server/SerialPortImpl.cpp
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Main/src-server/SerialPortImpl.cpp')
-rw-r--r--src/VBox/Main/src-server/SerialPortImpl.cpp787
1 files changed, 787 insertions, 0 deletions
diff --git a/src/VBox/Main/src-server/SerialPortImpl.cpp b/src/VBox/Main/src-server/SerialPortImpl.cpp
new file mode 100644
index 00000000..96082b0c
--- /dev/null
+++ b/src/VBox/Main/src-server/SerialPortImpl.cpp
@@ -0,0 +1,787 @@
+/* $Id: SerialPortImpl.cpp $ */
+/** @file
+ * VirtualBox COM class implementation
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#define LOG_GROUP LOG_GROUP_MAIN_SERIALPORT
+#include "SerialPortImpl.h"
+#include "MachineImpl.h"
+#include "VirtualBoxImpl.h"
+#include "GuestOSTypeImpl.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/cpp/utils.h>
+
+#include <VBox/settings.h>
+
+#include "AutoStateDep.h"
+#include "AutoCaller.h"
+#include "LoggingNew.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+// SerialPort private data definition
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+struct SerialPort::Data
+{
+ Data()
+ : fModified(false),
+ pMachine(NULL)
+ { }
+
+ bool fModified;
+ Machine * const pMachine;
+ const ComObjPtr<SerialPort> pPeer;
+ Backupable<settings::SerialPort> bd;
+};
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+DEFINE_EMPTY_CTOR_DTOR(SerialPort)
+
+HRESULT SerialPort::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void SerialPort::FinalRelease()
+{
+ uninit();
+ BaseFinalRelease();
+}
+
+// public initializer/uninitializer for internal purposes only
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the Serial Port object.
+ *
+ * @param aParent Handle of the parent object.
+ * @param aSlot Slot number the serial port is plugged into.
+ */
+HRESULT SerialPort::init(Machine *aParent, ULONG aSlot)
+{
+ LogFlowThisFunc(("aParent=%p, aSlot=%d\n", aParent, aSlot));
+
+ ComAssertRet(aParent, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data();
+
+ unconst(m->pMachine) = aParent;
+ /* m->pPeer is left null */
+
+ m->bd.allocate();
+
+ /* initialize data */
+ m->bd->ulSlot = aSlot;
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the Serial Port object given another serial port object
+ * (a kind of copy constructor). This object shares data with
+ * the object passed as an argument.
+ *
+ * @note This object must be destroyed before the original object
+ * it shares data with is destroyed.
+ *
+ * @note Locks @a aThat object for reading.
+ */
+HRESULT SerialPort::init(Machine *aParent, SerialPort *aThat)
+{
+ LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
+
+ ComAssertRet(aParent && aThat, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data();
+
+ unconst(m->pMachine) = aParent;
+ unconst(m->pPeer) = aThat;
+
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnRC(thatCaller.hrc());
+
+ AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+ m->bd.share(aThat->m->bd);
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the guest object given another guest object
+ * (a kind of copy constructor). This object makes a private copy of data
+ * of the original object passed as an argument.
+ *
+ * @note Locks @a aThat object for reading.
+ */
+HRESULT SerialPort::initCopy(Machine *aParent, SerialPort *aThat)
+{
+ LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
+
+ ComAssertRet(aParent && aThat, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data();
+
+ unconst(m->pMachine) = aParent;
+ /* pPeer is left null */
+
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnRC(thatCaller.hrc());
+
+ AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+ m->bd.attachCopy(aThat->m->bd);
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Uninitializes the instance and sets the ready flag to FALSE.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void SerialPort::uninit()
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+
+ m->bd.free();
+
+ unconst(m->pPeer) = NULL;
+ unconst(m->pMachine) = NULL;
+
+ delete m;
+ m = NULL;
+}
+
+// ISerialPort properties
+/////////////////////////////////////////////////////////////////////////////
+
+HRESULT SerialPort::getEnabled(BOOL *aEnabled)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aEnabled = m->bd->fEnabled;
+
+ return S_OK;
+}
+
+
+HRESULT SerialPort::setEnabled(BOOL aEnabled)
+{
+ LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
+
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->fEnabled != RT_BOOL(aEnabled))
+ {
+ m->bd.backup();
+ m->bd->fEnabled = RT_BOOL(aEnabled);
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT SerialPort::getHostMode(PortMode_T *aHostMode)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aHostMode = m->bd->portMode;
+
+ return S_OK;
+}
+
+HRESULT SerialPort::setHostMode(PortMode_T aHostMode)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->portMode != aHostMode)
+ {
+ switch (aHostMode)
+ {
+ case PortMode_RawFile:
+ if (m->bd->strPath.isEmpty())
+ return setError(E_INVALIDARG,
+ tr("Cannot set the raw file mode of the serial port %d "
+ "because the file path is empty or null"),
+ m->bd->ulSlot);
+ break;
+ case PortMode_HostPipe:
+ if (m->bd->strPath.isEmpty())
+ return setError(E_INVALIDARG,
+ tr("Cannot set the host pipe mode of the serial port %d "
+ "because the pipe path is empty or null"),
+ m->bd->ulSlot);
+ break;
+ case PortMode_HostDevice:
+ if (m->bd->strPath.isEmpty())
+ return setError(E_INVALIDARG,
+ tr("Cannot set the host device mode of the serial port %d "
+ "because the device path is empty or null"),
+ m->bd->ulSlot);
+ break;
+ case PortMode_TCP:
+ if (m->bd->strPath.isEmpty())
+ return setError(E_INVALIDARG,
+ tr("Cannot set the host device mode of the serial port %d "
+ "because the server address or TCP port is invalid"),
+ m->bd->ulSlot);
+ break;
+ case PortMode_Disconnected:
+ break;
+#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
+ case PortMode_32BitHack: /* (compiler warnings) */
+ AssertFailedBreak();
+#endif
+ }
+
+ m->bd.backup();
+ m->bd->portMode = aHostMode;
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return S_OK;
+}
+
+HRESULT SerialPort::getSlot(ULONG *aSlot)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aSlot = m->bd->ulSlot;
+
+ return S_OK;
+}
+
+
+HRESULT SerialPort::getIRQ(ULONG *aIRQ)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aIRQ = m->bd->ulIRQ;
+
+ return S_OK;
+}
+
+
+HRESULT SerialPort::setIRQ(ULONG aIRQ)
+{
+ /* check IRQ limits
+ * (when changing this, make sure it corresponds to XML schema */
+ if (aIRQ > 255)
+ return setError(E_INVALIDARG,
+ tr("Invalid IRQ number of the serial port %d: %lu (must be in range [0, %lu])"),
+ m->bd->ulSlot, aIRQ, 255);
+
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->ulIRQ != aIRQ)
+ {
+ m->bd.backup();
+ m->bd->ulIRQ = aIRQ;
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT SerialPort::getIOBase(ULONG *aIOBase)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aIOBase = m->bd->ulIOBase;
+
+ return S_OK;
+}
+
+HRESULT SerialPort::setIOBase(ULONG aIOBase)
+{
+ /* check IOBase limits
+ * (when changing this, make sure it corresponds to XML schema */
+ if (aIOBase > 0xFFFF)
+ return setError(E_INVALIDARG,
+ tr("Invalid I/O port base address of the serial port %d: %lu (must be in range [0, 0x%X])"),
+ m->bd->ulSlot, aIOBase, 0, 0xFFFF);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
+
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT hrc = S_OK;
+
+ if (m->bd->ulIOBase != aIOBase)
+ {
+ m->bd.backup();
+ m->bd->ulIOBase = aIOBase;
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return hrc;
+}
+
+HRESULT SerialPort::getPath(com::Utf8Str &aPath)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aPath = m->bd->strPath;
+
+ return S_OK;
+}
+
+
+HRESULT SerialPort::setPath(const com::Utf8Str &aPath)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aPath != m->bd->strPath)
+ {
+ HRESULT hrc = i_checkSetPath(aPath);
+ if (FAILED(hrc)) return hrc;
+
+ m->bd.backup();
+ m->bd->strPath = aPath;
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return S_OK;
+}
+
+HRESULT SerialPort::getServer(BOOL *aServer)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aServer = m->bd->fServer;
+
+ return S_OK;
+}
+
+HRESULT SerialPort::setServer(BOOL aServer)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->fServer != RT_BOOL(aServer))
+ {
+ m->bd.backup();
+ m->bd->fServer = RT_BOOL(aServer);
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return S_OK;
+}
+
+HRESULT SerialPort::getUartType(UartType_T *aUartType)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aUartType = m->bd->uartType;
+
+ return S_OK;
+}
+
+HRESULT SerialPort::setUartType(UartType_T aUartType)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.hrc())) return adep.hrc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->uartType != aUartType)
+ {
+ m->bd.backup();
+ m->bd->uartType = aUartType;
+
+ m->fModified = true;
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_SerialPorts);
+ mlock.release();
+
+ m->pMachine->i_onSerialPortChange(this);
+ }
+
+ return S_OK;
+}
+
+// public methods only for internal purposes
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Loads settings from the given port node.
+ * May be called once right after this object creation.
+ *
+ * @param data Configuration settings.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT SerialPort::i_loadSettings(const settings::SerialPort &data)
+{
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.hrc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ // simply copy
+ *m->bd.data() = data;
+
+ return S_OK;
+}
+
+/**
+ * Saves the port settings to the given port node.
+ *
+ * Note that the given Port node is completely empty on input.
+ *
+ * @param data Configuration settings.
+ *
+ * @note Locks this object for reading.
+ */
+HRESULT SerialPort::i_saveSettings(settings::SerialPort &data)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.hrc());
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ // simply copy
+ data = *m->bd.data();
+
+ return S_OK;
+}
+
+/**
+ * Returns true if any setter method has modified settings of this instance.
+ * @return
+ */
+bool SerialPort::i_isModified()
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ return m->fModified;
+}
+
+/**
+ * @note Locks this object for writing.
+ */
+void SerialPort::i_rollback()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.hrc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ m->bd.rollback();
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object (also
+ * for writing) if there is one.
+ */
+void SerialPort::i_commit()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.hrc());
+
+ /* sanity too */
+ AutoCaller peerCaller(m->pPeer);
+ AssertComRCReturnVoid(peerCaller.hrc());
+
+ /* lock both for writing since we modify both (pPeer is "master" so locked
+ * first) */
+ AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd.isBackedUp())
+ {
+ m->bd.commit();
+ if (m->pPeer)
+ {
+ /* attach new data to the peer and reshare it */
+ m->pPeer->m->bd.attach(m->bd);
+ }
+ }
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object
+ * represented by @a aThat (locked for reading).
+ */
+void SerialPort::i_copyFrom(SerialPort *aThat)
+{
+ AssertReturnVoid(aThat != NULL);
+
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.hrc());
+
+ /* sanity too */
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnVoid(thatCaller.hrc());
+
+ /* peer is not modified, lock it for reading (aThat is "master" so locked
+ * first) */
+ AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
+
+ /* this will back up current data */
+ m->bd.assignCopy(aThat->m->bd);
+}
+
+/**
+ * Applies the defaults for this serial port.
+ *
+ * @note This method currently assumes that the object is in the state after
+ * calling init(), it does not set defaults from an arbitrary state.
+ */
+void SerialPort::i_applyDefaults(GuestOSType *aOsType)
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.hrc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /* Set some more defaults. */
+ switch (m->bd->ulSlot)
+ {
+ case 0:
+ {
+ m->bd->ulIOBase = 0x3f8;
+ m->bd->ulIRQ = 4;
+ break;
+ }
+ case 1:
+ {
+ m->bd->ulIOBase = 0x2f8;
+ m->bd->ulIRQ = 3;
+ break;
+ }
+ case 2:
+ {
+ m->bd->ulIOBase = 0x3e8;
+ m->bd->ulIRQ = 4;
+ break;
+ }
+ case 3:
+ {
+ m->bd->ulIOBase = 0x2e8;
+ m->bd->ulIRQ = 3;
+ break;
+ }
+ default:
+ AssertMsgFailed(("Serial port slot %u exceeds limit\n", m->bd->ulSlot));
+ break;
+ }
+
+ uint32_t numSerialEnabled = 0;
+ if (aOsType)
+ numSerialEnabled = aOsType->i_numSerialEnabled();
+
+ /* Enable port if requested */
+ if (m->bd->ulSlot < numSerialEnabled)
+ {
+ m->bd->fEnabled = true;
+ }
+}
+
+bool SerialPort::i_hasDefaults()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.hrc(), true);
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( !m->bd->fEnabled
+ && m->bd->portMode == PortMode_Disconnected
+ && !m->bd->fServer)
+ {
+ /* Could be default, check the IO base and IRQ. */
+ switch (m->bd->ulSlot)
+ {
+ case 0:
+ if (m->bd->ulIOBase == 0x3f8 && m->bd->ulIRQ == 4)
+ return true;
+ break;
+ case 1:
+ if (m->bd->ulIOBase == 0x2f8 && m->bd->ulIRQ == 3)
+ return true;
+ break;
+ case 2:
+ if (m->bd->ulIOBase == 0x3e8 && m->bd->ulIRQ == 4)
+ return true;
+ break;
+ case 3:
+ if (m->bd->ulIOBase == 0x2e8 && m->bd->ulIRQ == 3)
+ return true;
+ break;
+ default:
+ AssertMsgFailed(("Serial port slot %u exceeds limit\n", m->bd->ulSlot));
+ break;
+ }
+
+ /* Detect old-style defaults (0x3f8, irq 4) in any slot, they are still
+ * in place for many VMs created by old VirtualBox versions. */
+ if (m->bd->ulIOBase == 0x3f8 && m->bd->ulIRQ == 4)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Validates COMSETTER(Path) arguments.
+ */
+HRESULT SerialPort::i_checkSetPath(const Utf8Str &str)
+{
+ AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
+
+ if ( ( m->bd->portMode == PortMode_HostDevice
+ || m->bd->portMode == PortMode_HostPipe
+ || m->bd->portMode == PortMode_TCP
+ || m->bd->portMode == PortMode_RawFile
+ ) && str.isEmpty()
+ )
+ return setError(E_INVALIDARG,
+ tr("Path of the serial port %d may not be empty or null in "
+ "host pipe, host device or TCP mode"),
+ m->bd->ulSlot);
+
+ return S_OK;
+}
+
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */