[Pkg-virtualbox-commits] [virtualbox] 02/05: Imported Upstream version 5.1.10-dfsg

Gianfranco Costamagna locutusofborg at moszumanska.debian.org
Tue Nov 22 12:28:11 UTC 2016


This is an automated email from the git hooks/post-receive script.

locutusofborg pushed a commit to branch master
in repository virtualbox.

commit a270b6658ef54d135807dab961a88d3dbdccf12c
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date:   Tue Nov 22 13:04:43 2016 +0100

    Imported Upstream version 5.1.10-dfsg
---
 Config.kmk                                         |   34 +-
 configure                                          |    2 +-
 doc/manual/en_US/user_Technical.xml                |   37 +-
 doc/manual/en_US/user_VBoxManage.xml               |    7 +-
 doc/manual/user_ChangeLogImpl.xml                  |  109 +-
 include/Makefile.kmk                               |    1 +
 include/VBox/err.h                                 |    7 +-
 include/VBox/param.h                               |   17 +-
 include/VBox/pci.h                                 |  617 +---
 include/VBox/types.h                               |    3 +
 include/VBox/vmm/iom.h                             |   18 +
 include/VBox/vmm/mm.h                              |    2 +-
 include/VBox/vmm/pdmaudioifs.h                     |    4 +
 include/VBox/vmm/pdmaudioifs_50.h                  |  788 ++++
 include/VBox/vmm/pdmdev.h                          |  505 ++-
 include/VBox/vmm/pdmpci.h                          |    2 +-
 include/VBox/vmm/pdmpcidev.h                       |  627 ++++
 .../VBox/vmm/pdmpcidevint.h                        |  163 +-
 include/VBox/vmm/pgm.h                             |   16 +-
 .../Additions/common/VBoxGuest/VBoxGuest-solaris.c |  267 +-
 .../Additions/common/VBoxGuest/VBoxGuest-win.cpp   |    3 +-
 src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp  |   33 +-
 .../Additions/common/VBoxGuest/VBoxGuestInternal.h |   12 +
 .../VBoxGuestLib/VBoxGuestR3LibAdditions.cpp       |    2 +-
 .../common/VBoxService/VBoxServiceVMInfo-win.cpp   |   12 +-
 src/VBox/Additions/common/crOpenGL/dri_util.c      |    2 +-
 src/VBox/Additions/freebsd/Makefile.kmk            |    2 +-
 src/VBox/Additions/linux/Makefile.kmk              |    2 +-
 src/VBox/Additions/linux/drm/vbox_ttm.c            |    4 +-
 src/VBox/Additions/linux/installer/vboxadd-x11.sh  |    4 +-
 src/VBox/Additions/linux/installer/vboxadd.sh      |    6 +-
 src/VBox/Additions/linux/sharedfolders/dirops.c    |   15 +-
 src/VBox/Devices/Audio/AudioMixer.cpp              |    2 +-
 .../Devices/Audio/{DevIchHda.cpp => DevHDA.cpp}    |   19 +-
 .../Audio/{DevIchHdaCommon.h => DevHDACommon.h}    |    2 +-
 src/VBox/Devices/Audio/DevIchAc97.cpp              |   35 +-
 src/VBox/Devices/Audio/DrvHostCoreAudio.cpp        |    2 +-
 src/VBox/Devices/Audio/DrvHostPulseAudio.cpp       |   18 +-
 .../Audio/{DevIchHdaCodec.cpp => HDACodec.cpp}     |    6 +-
 .../Devices/Audio/{DevIchHdaCodec.h => HDACodec.h} |    2 +-
 src/VBox/Devices/Audio/alsa_stubs.c                |    2 +-
 src/VBox/Devices/Audio/pulse_stubs.c               |    4 +-
 src/VBox/Devices/Audio_50/AudioMixBuffer.cpp       | 1756 +++++++++
 src/VBox/Devices/Audio_50/AudioMixBuffer.h         |   82 +
 src/VBox/Devices/Audio_50/AudioMixer.cpp           |  520 +++
 src/VBox/Devices/Audio_50/AudioMixer.h             |  113 +
 .../{Audio/DevIchHda.cpp => Audio_50/DevHDA.cpp}   | 3828 +++++++-------------
 .../Devices/{Audio => Audio_50}/DevIchAc97.cpp     | 2062 +++++------
 .../Devices/{Audio => Audio_50}/DevIchHdaCodec.h   |   83 +-
 src/VBox/Devices/Audio_50/DevSB16.cpp              | 2449 +++++++++++++
 src/VBox/Devices/Audio_50/DrvAudio.cpp             | 2627 ++++++++++++++
 src/VBox/Devices/Audio_50/DrvAudio.h               |  156 +
 src/VBox/Devices/Audio_50/DrvAudioCommon.cpp       |  413 +++
 src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp     | 1425 ++++++++
 src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp     | 2278 ++++++++++++
 src/VBox/Devices/Audio_50/DrvHostDSound.cpp        | 2292 ++++++++++++
 src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp     |  342 ++
 src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp      | 1006 +++++
 src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp    | 1257 +++++++
 .../DevIchHdaCodec.cpp => Audio_50/HDACodec.cpp}   | 2147 +++++------
 src/VBox/Devices/Audio_50/Makefile.kup             |    0
 src/VBox/Devices/Audio_50/alsa_mangling.h          |   55 +
 src/VBox/Devices/{Audio => Audio_50}/alsa_stubs.c  |   20 +-
 src/VBox/Devices/Audio_50/alsa_stubs.h             |   21 +
 src/VBox/Devices/Audio_50/pulse_mangling.h         |   69 +
 src/VBox/Devices/{Audio => Audio_50}/pulse_stubs.c |   18 +-
 src/VBox/Devices/Audio_50/pulse_stubs.h            |   21 +
 src/VBox/Devices/Audio_50/sys-queue.h              |  241 ++
 src/VBox/Devices/Audio_50/testcase/Makefile.kmk    |   41 +
 .../Audio_50/testcase/tstAudioMixBuffer.cpp        |  592 +++
 src/VBox/Devices/Bus/DevPCI.cpp                    |  470 +--
 src/VBox/Devices/Bus/DevPciIch9.cpp                |  517 +--
 src/VBox/Devices/Bus/DevPciMerge1.cpp.h            |  239 ++
 src/VBox/Devices/Bus/MsiCommon.cpp                 |   50 +-
 src/VBox/Devices/Bus/MsiCommon.h                   |   20 +-
 src/VBox/Devices/Bus/MsixCommon.cpp                |   65 +-
 src/VBox/Devices/Bus/PciInline.h                   |  101 +
 src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd      |  Bin 2097152 -> 2097152 bytes
 src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd      |  Bin 2097152 -> 2097152 bytes
 src/VBox/Devices/GIMDev/GIMDev.cpp                 |   10 +-
 .../Graphics/BIOS/VBoxVgaBiosAlternative286.asm    |  262 +-
 .../Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum |    2 +-
 .../Graphics/BIOS/VBoxVgaBiosAlternative386.asm    |  262 +-
 .../Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum |    2 +-
 .../Graphics/BIOS/VBoxVgaBiosAlternative8086.asm   |  264 +-
 .../BIOS/VBoxVgaBiosAlternative8086.md5sum         |    2 +-
 src/VBox/Devices/Graphics/DevVGA-SVGA.cpp          |   20 +-
 src/VBox/Devices/Graphics/DevVGA-SVGA.h            |   15 +-
 src/VBox/Devices/Graphics/DevVGA.cpp               |  110 +-
 src/VBox/Devices/Graphics/DevVGA.h                 |    2 +-
 src/VBox/Devices/Makefile.kmk                      |   52 +-
 src/VBox/Devices/Network/DevE1000.cpp              |  110 +-
 src/VBox/Devices/Network/DevPCNet.cpp              |   65 +-
 src/VBox/Devices/Network/DevVirtioNet.cpp          |   13 +-
 src/VBox/Devices/Network/lwip-new/src/api/tcpip.c  |    2 +
 .../Devices/Network/lwip-new/src/core/tcp_in.c     |   39 +-
 src/VBox/Devices/Network/slirp/slirp.c             |    9 +-
 src/VBox/Devices/Network/slirp/slirp.h             |   27 +-
 src/VBox/Devices/Network/slirp/socket.c            |   32 +-
 .../Devices/PC/BIOS/VBoxBiosAlternative286.asm     |    4 +-
 .../Devices/PC/BIOS/VBoxBiosAlternative286.md5sum  |    2 +-
 .../Devices/PC/BIOS/VBoxBiosAlternative386.asm     |    4 +-
 .../Devices/PC/BIOS/VBoxBiosAlternative386.md5sum  |    2 +-
 .../Devices/PC/BIOS/VBoxBiosAlternative8086.asm    |    4 +-
 .../Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum |    2 +-
 src/VBox/Devices/PC/DevACPI.cpp                    |   49 +-
 src/VBox/Devices/PC/DevLPC.cpp                     |   81 +-
 src/VBox/Devices/Samples/DevPlayground.cpp         |  107 +-
 src/VBox/Devices/Serial/DevSerial.cpp              |   30 +-
 src/VBox/Devices/Storage/DevAHCI.cpp               |   39 +-
 src/VBox/Devices/Storage/DevATA.cpp                |   50 +-
 src/VBox/Devices/Storage/DevBusLogic.cpp           |    9 +-
 src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp       |   12 +-
 src/VBox/Devices/USB/DevOHCI.cpp                   |   32 +-
 .../Devices/USB/linux/USBProxyDevice-linux.cpp     |   16 +-
 src/VBox/Devices/VMMDev/VMMDev.cpp                 |   66 +-
 src/VBox/Devices/VMMDev/VMMDevState.h              |    2 +-
 src/VBox/Devices/VirtIO/Virtio.cpp                 |   45 +-
 src/VBox/Devices/VirtIO/Virtio.h                   |    2 +-
 src/VBox/Devices/build/VBoxDD.cpp                  |    4 +
 src/VBox/Devices/build/VBoxDD.h                    |    4 +
 src/VBox/Devices/testcase/tstDeviceStructSize.cpp  |    6 +-
 .../Devices/testcase/tstDeviceStructSizeRC.cpp     |   50 +-
 src/VBox/Disassembler/DisasmCore.cpp               |    2 +-
 src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp   |    5 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts   |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts |   32 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts |   99 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts |   51 +-
 .../Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts   |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts   |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts |    8 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_km_KH.ts   |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts |  353 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts   |   46 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts |   55 +-
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts |    4 +
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts |  482 +--
 src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts   |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts   |    4 +
 .../Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts   |    4 +
 src/VBox/Frontends/VirtualBox/nls/qt_el.ts         |  183 +-
 .../src/converter/UIConverterBackendGlobal.cpp     |   42 +-
 .../VirtualBox/src/extradata/UIExtraDataDefs.h     |   22 +-
 .../VirtualBox/src/globals/UIActionPool.h          |    1 +
 src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h |   11 +
 .../src/globals/UIDesktopWidgetWatchdog.cpp        |  208 +-
 .../src/globals/UIDesktopWidgetWatchdog.h          |   17 +-
 .../Frontends/VirtualBox/src/globals/UIIconPool.h  |    4 +-
 .../VirtualBox/src/globals/UIMessageCenter.cpp     |   13 +-
 src/VBox/Frontends/VirtualBox/src/main.cpp         |    2 +-
 .../platform/darwin/UIAbstractDockIconPreview.h    |    2 +-
 .../VirtualBox/src/runtime/UIActionPoolRuntime.cpp |   66 +
 .../VirtualBox/src/runtime/UIActionPoolRuntime.h   |    2 +
 .../VirtualBox/src/runtime/UIDnDMIMEData.cpp       |    2 +-
 .../VirtualBox/src/runtime/UIFrameBuffer.cpp       |   20 +-
 .../VirtualBox/src/runtime/UIMachineLogic.cpp      |   38 +
 .../VirtualBox/src/runtime/UIMachineLogic.h        |    2 +
 .../src/runtime/UIMenuBarEditorWindow.cpp          |   14 +
 .../Frontends/VirtualBox/src/runtime/UISession.cpp |   62 +-
 .../src/settings/machine/UIMachineSettingsUSB.h    |    1 +
 .../machine/UIMachineSettingsUSBFilterDetails.cpp  |    2 +-
 .../src/wizards/newvd/UIWizardNewVDPageBasic3.cpp  |    4 +-
 .../src/wizards/newvm/UIWizardNewVMPageBasic1.cpp  |   10 +-
 .../Support/win/SUPHardenedVerifyImage-win.cpp     |   46 +
 .../Support/win/SUPR3HardenedMain-win.cpp          |    2 +-
 .../HostDrivers/Support/win/VBoxSupLib-win.cpp     |    2 +-
 .../SharedOpenGL/crserverlib/server_main.c         |    2 +
 src/VBox/Installer/darwin/Makefile.kmk             |    6 -
 src/VBox/Installer/linux/distributions_rpm         |    1 +
 src/VBox/Installer/linux/rpm/rules                 |    2 +-
 src/VBox/Installer/solaris/Makefile.kmk            |    2 +-
 src/VBox/Installer/win/Makefile.kmk                |    1 +
 src/VBox/Installer/win/VBoxMergeApp.wxi            |   17 +-
 src/VBox/Installer/win/VBoxMergeCOM32On64.wxs      |    4 +-
 src/VBox/Installer/win/VirtualBox_TypeLib.xsl      |    2 +-
 .../win/VirtualBox_TypeLibWithInterfaces.xsl       |    2 +-
 src/VBox/Main/Makefile.kmk                         |    7 +-
 src/VBox/Main/cbinding/VBoxCAPIGlue.c              |   11 +-
 src/VBox/Main/idl/VirtualBox.xidl                  |    2 +-
 src/VBox/Main/include/DrvAudioVRDE_50.h            |   64 +
 src/VBox/Main/include/DrvAudioVideoRec_50.h        |   62 +
 src/VBox/Main/src-all/Global.cpp                   |    2 +-
 src/VBox/Main/src-client/DisplayImpl.cpp           |    3 +
 src/VBox/Main/src-client/DrvAudioVRDE_50.cpp       |  618 ++++
 src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp   |  911 +++++
 src/VBox/Main/src-client/GuestProcessImpl.cpp      |    2 +-
 .../Main/src-server/linux/HostDnsServiceLinux.cpp  |    5 +
 src/VBox/Main/xml/Settings.cpp                     |   21 +-
 src/VBox/Main/xml/VirtualBox-settings.xsd          |    8 +-
 src/VBox/NetworkServices/NAT/RTWinPoll.cpp         |   36 +-
 src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp    |    3 +
 src/VBox/NetworkServices/NAT/proxy_pollmgr.c       |    5 +
 src/VBox/NetworkServices/NAT/pxtcp.c               |    4 +
 src/VBox/Runtime/common/crypto/pemfile.cpp         |    1 +
 src/VBox/Runtime/common/crypto/pkcs7-verify.cpp    |    2 +-
 src/VBox/Runtime/common/crypto/spc-template.h      |    2 +-
 src/VBox/Runtime/common/crypto/x509-certpaths.cpp  |    2 +-
 src/VBox/Runtime/common/err/errmsgxpcom.cpp        |    1 +
 src/VBox/Runtime/common/misc/uri.cpp               |    2 +-
 src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c  |   18 +
 src/VBox/Runtime/r3/win/mp-win.cpp                 |    2 +-
 src/VBox/Runtime/tools/RTSignTool.cpp              |   10 +-
 src/VBox/Storage/VDI.cpp                           |  201 +-
 src/VBox/Storage/testcase/VDScriptInterp.cpp       |    2 +-
 src/VBox/VMM/VMMAll/PGMAllHandler.cpp              |  294 +-
 src/VBox/VMM/VMMAll/PGMAllPhys.cpp                 |    2 +-
 src/VBox/VMM/VMMR0/HMVMXR0.cpp                     |    4 +-
 src/VBox/VMM/VMMR0/PDMR0Device.cpp                 |   72 +-
 src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp                 |    4 +-
 src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp               |    2 +-
 src/VBox/VMM/VMMR3/DBGFBp.cpp                      |    2 +-
 src/VBox/VMM/VMMR3/GIM.cpp                         |    2 +-
 src/VBox/VMM/VMMR3/IOM.cpp                         |  213 ++
 src/VBox/VMM/VMMR3/MMHyper.cpp                     |   19 +-
 src/VBox/VMM/VMMR3/PDM.cpp                         |   61 +-
 src/VBox/VMM/VMMR3/PDMBlkCache.cpp                 |    2 +-
 src/VBox/VMM/VMMR3/PDMDevHlp.cpp                   |  705 ++--
 src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp               |    6 +-
 src/VBox/VMM/VMMR3/PDMDevice.cpp                   |    9 +-
 src/VBox/VMM/VMMR3/PDMDriver.cpp                   |   11 +
 src/VBox/VMM/VMMR3/PGM.cpp                         |    2 +-
 src/VBox/VMM/VMMR3/PGMPhys.cpp                     | 1150 ++++--
 src/VBox/VMM/VMMR3/PGMSavedState.cpp               |  348 +-
 src/VBox/VMM/VMMRC/PDMRCDevice.cpp                 |   69 +-
 src/VBox/VMM/include/MMInternal.h                  |    6 +
 src/VBox/VMM/include/PDMInternal.h                 |   58 +-
 src/VBox/VMM/include/PGMInline.h                   |    2 +-
 src/VBox/VMM/include/PGMInternal.h                 |   88 +-
 src/VBox/VMM/testcase/tstVMStruct.h                |   46 +-
 src/VBox/VMM/testcase/tstVMStructSize.cpp          |    2 +-
 .../bootsectors/bootsector2-common-traprec.mac     |    2 +-
 .../bootsectors/bs3-cpu-basic-2-template.c         |    2 +-
 .../ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c |    2 +-
 .../bootsectors/bs3kit/bs3-c16-Trap16Generic.asm   |    8 +-
 .../bs3kit/bs3-c16-TrapRmV86Generic.asm            |    4 +-
 .../bootsectors/bs3kit/bs3-c32-Trap32Generic.asm   |    2 +-
 .../bootsectors/bs3kit/bs3-c64-Trap64Generic.asm   |    4 +-
 src/VBox/ValidationKit/testanalysis/diff.py        |    4 +-
 src/VBox/ValidationKit/testanalysis/reporting.py   |    4 +-
 .../ValidationKit/testmanager/webui/wuimain.py     |    4 +-
 src/bldprogs/scmstream.h                           |    2 +-
 src/libs/Makefile.kmk                              |    2 +-
 .../ipc/ipcd/client/src/ipcConnectionUnix.cpp      |    8 +-
 src/libs/xpcom18a4/python/src/PyIID.cpp            |    9 +
 src/libs/xpcom18a4/python/src/PyXPCOM.h            |    8 +
 src/libs/xpcom18a4/python/src/TypeObject.cpp       |    8 +
 src/libs/xpcom18a4/xpcom/base/nsError.h            |    3 +
 .../xpcom/components/nsComponentManager.cpp        |    3 +-
 src/recompiler/VBoxRecompiler.c                    |    2 +-
 270 files changed, 30551 insertions(+), 9491 deletions(-)

diff --git a/Config.kmk b/Config.kmk
index 94b1dc8..3d30e65 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -208,7 +208,7 @@ VBOX_VERSION_MINOR = 1
 # This is the current build number. It should be increased every time we publish a
 # new build. The define is available in every source file. Only even build numbers
 # will be published, odd numbers are set during development.
-VBOX_VERSION_BUILD = 8
+VBOX_VERSION_BUILD = 10
 # The raw version string. This *must not* contain any other information/fields than
 # major, minor and build revision (as it is now) -- also will be used for host/guest version
 # comparison.
@@ -235,6 +235,9 @@ ifneq ($(VBOX_RELEASE_EXACT_MATCH),)
  export VBOX_EXTPACKS_SH_MODE      = release
 endif
 
+# by default use the old 5.0 audio code as the new code still has too many regressions
+VBOX_WITH_AUDIO_50 := 1
+
 # Some info on the vendor
 VBOX_VENDOR       = Oracle Corporation
 VBOX_VENDOR_SHORT = Oracle
@@ -1166,6 +1169,18 @@ ifdef VBOX_OSE
 endif
 
 #
+# Audio: Which code base to use.
+# This can be overriden in LocalConfig.kmk.
+#
+ifdef VBOX_WITH_AUDIO_50
+ VBOX_AUDIO_PATH_SOURCES=Audio_50
+ VBOX_AUDIO_FILE_SUFFIX=_50
+else
+ VBOX_AUDIO_PATH_SOURCES=Audio
+ VBOX_AUDIO_FILE_SUFFIX=
+endif
+
+#
 # VBOX_WITHOUT_HARDENING is for developers (put in LocalConfig.kmk).
 # Note that this is a bit rough since hardening governs more than one
 # variable...  Also note that we allow VBOX_WITH_HARDENING=1 on the
@@ -2462,8 +2477,9 @@ else
  # This is kind of bad, the returned string needs to be re-evaluated before use.
  # The reason for this hack is that the windows kmk_ash cannot deal with $((1+1)).
  # Some versions of gcc (e.g. openSUSE11) return only major.minor on `gcc -dumpversion`.
+ # gcc-5 of openSUSE42.1 only returns the major version on `gcc -dumpversion`!
  VBOX_GCC_VERSION = $(shell \
-    $(1) -dumpversion | $(SED_EXT) 's|\([0-9]\)\.\([0-9]\)\.\{0,1\}\([0-9]\{0,1\}\).*|$$(int-add $$(int-mul 10000, \1), $$(int-mul 100, \2), $$(firstword \3 0))|' )
+    $(1) -dumpversion | $(SED_EXT) 's|\([0-9]\)\.\{0,1\}\([0-9]\{0,1\}\)\.\{0,1\}\([0-9]\{0,1\}\).*|$$(int-add $$(int-mul 10000, \1), $$(int-mul 100, $$(firstword \2 0)), $$(firstword \3 0))|' )
 endif
 
 # Find MinGW cross compilers for EFI on non-windows systems. We need to probe
@@ -2894,6 +2910,17 @@ ifdef VBOX_WITH_NO_GCC_WARNING_POLICY
  $(info build debug: VBOX_WITH_NO_GCC_WARNING_POLICY is enabled)
 endif
 
+#
+# We compile the kernel driver/module and related runtime libraries with C++.
+# This does not work for g++-4.8 and recent Linux kernels.
+#
+ifeq ($(BUILD_TARGET),linux)
+ ifeq ($(int-div $(VBOX_GCC_VERSION_CXX),100), 408)
+  VBOX_WITH_VBOXDRV =
+  VBOX_WITH_ADDITION_DRIVERS =
+ endif
+endif
+
 
 #
 # Misc stuff that should be after including DynamicConfig.kmk.
@@ -5809,6 +5836,7 @@ ifdef VBOX_WITH_QTGUI
   TEMPLATE_VBOXQTGUIEXE_RCCTOOL = QT5
   TEMPLATE_VBOXQTGUIEXE_LRCTOOL = QT5
   TEMPLATE_VBOXQTGUIEXE_SDKS = QT5
+  TEMPLATE_VBOXQTGUIEXE_MOCDEFS.darwin += QT_VERSION=0x050602
  endif # VBOX_WITH_QTGUI_V5
  TEMPLATE_VBOXQTGUIEXE_QT_INFIX = $(VBOX_QT_INFIX)
  TEMPLATE_VBOXQTGUIEXE_DEFS = IN_RING3 QT_NO_DEBUG QT_THREAD_SUPPORT QT_SHARED HAVE_CONFIG_H $(ARCH_BITS_DEFS)
@@ -6856,7 +6884,7 @@ endif
 SVN                    ?= svn$(HOSTSUFF_EXE)
 VBOX_SVN_REV_KMK        = $(PATH_OUT)/revision.kmk
 ifndef VBOX_SVN_REV
- VBOX_SVN_REV_FALLBACK := $(patsubst %:,,  $Rev: 111374 $  )
+ VBOX_SVN_REV_FALLBACK := $(patsubst %:,,  $Rev: 112026 $  )
  VBOX_SVN_DEP          := $(firstword $(wildcard $(PATH_ROOT)/.svn/wc.db $(abspath $(PATH_ROOT)/../.svn/wc.db) $(abspath $(PATH_ROOT)/../../.svn/wc.db) $(PATH_ROOT)/.svn/entries))
  ifeq ($(which $(SVN)),)
   VBOX_SVN_DEP         :=
diff --git a/configure b/configure
index ff7545d..a63bf8c 100755
--- a/configure
+++ b/configure
@@ -2119,7 +2119,7 @@ extern "C" int main(void)
 }
 EOF
   found=
-  SUPPYTHONLIBS="python2.7 python2.6 python3.1 python3.2 python3.3 python3.4 python3.5 python3.5m"
+  SUPPYTHONLIBS="python2.7 python2.6 python3.1 python3.2 python3.3 python3.4 python3.4m python3.5 python3.5m"
   for p in $PYTHONDIR; do
     for d in $SUPPYTHONLIBS; do
       for b in lib/x86_64-linux-gnu lib/i386-linux-gnu lib64 lib/64 lib; do
diff --git a/doc/manual/en_US/user_Technical.xml b/doc/manual/en_US/user_Technical.xml
index 527730a..537a0e2 100644
--- a/doc/manual/en_US/user_Technical.xml
+++ b/doc/manual/en_US/user_Technical.xml
@@ -34,21 +34,32 @@
 
       <itemizedlist>
         <listitem>
-          <para>On Windows, this is
-          <computeroutput>%HOMEDRIVE%%HOMEPATH%</computeroutput>; typically
-          something like <computeroutput>C:\Documents and
-          Settings\Username\</computeroutput>.</para>
-        </listitem>
-
-        <listitem>
-          <para>On Mac OS X, this is
+          <para>On Windows, this is the location returned by the
+          <computeroutput>SHGetFolderPath</computeroutput> function of the
+          Windows system library Shell32.dll, asking for the user profile. Only
+          on very old Windows versions which don't have this function
+          or where it unexpectedly returns an error, there is a fallback based
+          on environment variables: first 
+          <computeroutput>%USERPROFILE%</computeroutput> is checked, if it
+          doesn't exist then an attempt with
+          <computeroutput>%HOMEDRIVE%%HOMEPATH%</computeroutput> is made.
+          Typical value is
+          <computeroutput>C:\Users\username</computeroutput>.</para>
+        </listitem>
+
+        <listitem>
+          <para>On Linux, Mac OS X and Solaris, this is generally taken from
+          the environment variable <computeroutput>$HOME</computeroutput>,
+          except for the user
+          <computeroutput>root</computeroutput> for which it's taken from the
+          account database (as a workaround for the frequent trouble caused
+          by users using VirtualBox in combination with the tool
+          <computeroutput>sudo</computeroutput> which by default doesn't reset
+          the environment variable <computeroutput>$HOME</computeroutput>).
+          Typical value on Linux and Solaris is 
+          <computeroutput>/home/username</computeroutput> and on Mac OS X
           <computeroutput>/Users/username</computeroutput>.</para>
         </listitem>
-
-        <listitem>
-          <para>On Linux and Solaris, this is
-          <computeroutput>/home/username</computeroutput>.</para>
-        </listitem>
       </itemizedlist>
 
       <para>For simplicity, we will abbreviate this as
diff --git a/doc/manual/en_US/user_VBoxManage.xml b/doc/manual/en_US/user_VBoxManage.xml
index 8585294..8811fa5 100644
--- a/doc/manual/en_US/user_VBoxManage.xml
+++ b/doc/manual/en_US/user_VBoxManage.xml
@@ -3176,9 +3176,10 @@ Virtual system 0:
 
     <screen>VBoxManage storagectl       <uuid|vmname>
                             --name <name>
-                            [--add <ide/sata/scsi/floppy>]
-                            [--controller <LsiLogic|LSILogicSAS|BusLogic|
-                                          IntelAhci|PIIX3|PIIX4|ICH6|I82078|usb>]
+                            [--add ide|sata|scsi|floppy|sas|usb|pcie]
+                            [--controller LSILogic|LSILogicSAS|BusLogic|
+                                          IntelAhci|PIIX3|PIIX4|ICH6|I82078|
+                                          USB|NVMe]
                             [--portcount <1-30>]
                             [--hostiocache on|off]
                             [--bootable on|off]
diff --git a/doc/manual/user_ChangeLogImpl.xml b/doc/manual/user_ChangeLogImpl.xml
index ea202d5..8aa7417 100644
--- a/doc/manual/user_ChangeLogImpl.xml
+++ b/doc/manual/user_ChangeLogImpl.xml
@@ -3,6 +3,111 @@
 <chapter> <!-- HACK ALERT! Seems we must have a single top level element for xi:include to work.
                            So, we use chapter and xpointer="xpointer(/chapter/)" with xi:include. -->
   <sect1>
+    <title>Version 5.1.10 (2016-11-21)</title>
+
+    <para>This is a maintenance release. The following items were fixed and/or
+      added:</para>
+
+    <itemizedlist>
+
+      <listitem>
+        <para>GUI: the USB filter settings dialog should allow to specify the
+          USB revision in hexadecimal format (bug #15400)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: fixed crash on certain hosts when pressing certain key
+          combinations (Windows hosts only; bug #15719)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: fixed issue with updating the available-geometry on
+          host-screen work-area resize</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: don't crash / hang on certain environments if accessibility
+          support is enabled</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: fixed various issues in Unscaled HiDPI Output mode
+          (bug #15707)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: extend the VM Input menu with
+          <emphasis>Print Screen</emphasis>-related actions</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: improved handling of inserting the Guest Additions ISO image
+          by trying all available optical drives rather than only the first one
+          and by not asking the user if he wants to force unmounting (which
+          doesn't work in most cases anyway)</para>
+      </listitem>
+
+      <listitem>
+        <para>API: default to RTC using UTC for Solaris 11 guests</para>
+      </listitem>
+
+      <listitem>
+        <para>Settings: be less restrictive when reading a VM configuration
+          containing a host-only adapter without an interface name</para>
+      </listitem>
+
+      <listitem>
+        <para>Storage: fixed resizing VDI images resulting in an
+          unbootable image under certain circumstances (bug #15983)</para>
+      </listitem>
+
+      <listitem>
+        <para>NAT: fixed several 5.1.8 regressions on Mac OS X and Windows
+          hosts (bug #16084)</para>
+      </listitem>
+
+      <listitem>
+        <para>Audio: fixed a few 5.1.x regressions by using the audio code
+          from 5.0.x until the audio overhaul is completed</para>
+      </listitem>
+
+      <listitem>
+        <para>VBoxManage: fixed documentation of the
+          <emphasis>storagectl</emphasis> command (bug #15971)</para>
+      </listitem>
+
+      <listitem>
+        <para>Build system: another fix for building VirtualBox on systems
+          which default to Python 3</para>
+      </listitem>
+
+      <listitem>
+        <para>Windows hosts: hardening fix for Windows 10 build 14971 (bug #16202)</para>
+      </listitem>
+
+      <listitem>
+        <para>Windows Additions: properly start the VirtualBox guest services even
+          if the guest user name contains special characters (bug #15982)</para>
+      </listitem>
+
+      <listitem>
+        <para>Solaris Additions: fixed preemptible mouse notification callback being
+          executed under a spinlock for Solaris guests</para>
+      </listitem>
+
+      <listitem>
+        <para>Linux hosts / guests: Linux 4.9 fixes (bugs #16155 and #16064)</para>
+      </listitem>
+
+      <listitem>
+        <para>Linux Additions: fixed Linux kernel module override rule
+          (thanks Mark Furneaux)</para>
+      </listitem>
+
+    </itemizedlist>
+  </sect1>
+
+  <sect1>
     <title>Version 5.1.8 (2016-10-18)</title>
 
     <para>This is a maintenance release. The following items were fixed and/or
@@ -27,7 +132,7 @@
 
       <listitem>
         <para>NAT: fixed parsing of port-forwarding rules with a name which
-          contains a slah (bug #16002)</para>
+          contains a slash (bug #16002)</para>
       </listitem>
 
       <listitem>
@@ -219,7 +324,7 @@
       </listitem>
 
       <listitem>
-        <para>Audio: fixed stream access mode with OSS backend (5.1 regression, 
+        <para>Audio: fixed stream access mode with OSS backend (5.1 regression,
           thanks to Jung-uk Kim)</para>
       </listitem>
 
diff --git a/include/Makefile.kmk b/include/Makefile.kmk
index 8bd17fc..d67d4d5 100644
--- a/include/Makefile.kmk
+++ b/include/Makefile.kmk
@@ -77,6 +77,7 @@ hdrs := $(filter-out \
 	VBox/dbus-calls.h \
 	VBox/VDEPlugSymDefs.h \
 	VBox/VBoxKeyboard.h \
+	VBox/vmm/pdmpcidevint.h \
 	iprt/runtime-loader.h \
 	iprt/mangling.h \
 	\
diff --git a/include/VBox/err.h b/include/VBox/err.h
index 12ba5ff..4638902 100644
--- a/include/VBox/err.h
+++ b/include/VBox/err.h
@@ -519,6 +519,8 @@
 #define VERR_PGM_INVALID_LARGE_PAGE_RANGE       (-1645)
 /** Don't mess around with ballooned pages. */
 #define VERR_PGM_PHYS_PAGE_BALLOONED            (-1646)
+/** Internal processing error \#1 in page access handler code. */
+#define VERR_PGM_HANDLER_IPE_1                  (-1647)
 
 
 /** pgmPhysPageMapCommon encountered PGMPAGETYPE_MMIO2_ALIAS_MMIO. */
@@ -587,9 +589,12 @@
 #define VERR_PGM_PCI_PASSTHRU_MISCONFIG         (-1682)
 /** Too many MMIO2 ranges. */
 #define VERR_PGM_TOO_MANY_MMIO2_RANGES          (-1683)
-/** Internal processing error in the PGM physial page mapping code dealing
+/** Internal processing error in the PGM physical page mapping code dealing
  * with MMIO2 pages. */
 #define VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE        (-1684)
+/** Internal processing error in the PGM physcal page handling code related to
+ *  MMIO/MMIO2. */
+#define VERR_PGM_PHYS_MMIO_EX_IPE               (-1685)
 /** @} */
 
 
diff --git a/include/VBox/param.h b/include/VBox/param.h
index 19b313e..f3c0001 100644
--- a/include/VBox/param.h
+++ b/include/VBox/param.h
@@ -38,7 +38,11 @@
 
 /** The maximum number of pages that can be allocated and mapped
  * by various MM, PGM and SUP APIs. */
-#define VBOX_MAX_ALLOC_PAGE_COUNT   (256U * _1M / PAGE_SIZE)
+#if ARCH_BITS == 64
+# define VBOX_MAX_ALLOC_PAGE_COUNT   (_512M / PAGE_SIZE)
+#else
+# define VBOX_MAX_ALLOC_PAGE_COUNT   (_256M / PAGE_SIZE)
+#endif
 
 /** @def VBOX_WITH_PAGE_SHARING
  * Enables the page sharing code.
@@ -84,6 +88,17 @@
 #endif
 /** The default size of the below 4GB RAM hole. */
 #define MM_RAM_HOLE_SIZE_DEFAULT    (512U * _1M)
+/** The maximum 64-bit MMIO BAR size.
+ * @remarks There isn't really any limit here other than the size of the
+ *          tracking structures we need (around 1/256 of the size). */
+#if HC_ARCH_BITS == 64
+# define MM_MMIO_64_MAX             _1T
+#else
+# define MM_MMIO_64_MAX             (_1G64 * 16)
+#endif
+/** The maximum 32-bit MMIO BAR size. */
+#define MM_MMIO_32_MAX              _2G
+
 /** @} */
 
 
diff --git a/include/VBox/pci.h b/include/VBox/pci.h
index dcc6008..4bed46c 100644
--- a/include/VBox/pci.h
+++ b/include/VBox/pci.h
@@ -1,5 +1,5 @@
 /** @file
- * PCI - The PCI Controller And Devices. (DEV)
+ * PCI - The PCI Controller And Devices Constants. (DEV)
  */
 
 /*
@@ -35,9 +35,6 @@
  * @{
  */
 
-/** Pointer to a PCI device. */
-typedef struct PCIDevice *PPCIDEVICE;
-
 
 /**
  * PCI configuration word 4 (command) and word 6 (status).
@@ -73,29 +70,6 @@ typedef enum PCIADDRESSSPACE
 } PCIADDRESSSPACE;
 
 
-/**
- * Callback function for mapping an PCI I/O region.
- *
- * @return VBox status code.
- * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param   iRegion         The region number.
- * @param   GCPhysAddress   Physical address of the region. If enmType is PCI_ADDRESS_SPACE_IO, this
- *                          is an I/O port, otherwise it's a physical address.
- *
- *                          NIL_RTGCPHYS indicates that a MMIO2 mapping is about to be unmapped and
- *                          that the device deregister access handlers for it and update its internal
- *                          state to reflect this.
- *
- * @param   enmType         One of the PCI_ADDRESS_SPACE_* values.
- *
- * @remarks Called with the PDM lock held.  The device lock is NOT take because
- *          that is very likely be a lock order violation.
- */
-typedef DECLCALLBACK(int) FNPCIIOREGIONMAP(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
-                                           RTGCPHYS cb, PCIADDRESSSPACE enmType);
-/** Pointer to a FNPCIIOREGIONMAP() function. */
-typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP;
-
 
 /** @name PCI Configuration Space Registers
  * @{ */
@@ -467,589 +441,29 @@ typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP;
 #define  VBOX_PCI_EXP_RTSTA_PME_PENDING 0x00020000 /* PME is Pending */
 
 
-/**
- * Callback function for reading from the PCI configuration space.
- *
- * @returns The register value.
- * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param   Address         The configuration space register address. [0..4096]
- * @param   cb              The register size. [1,2,4]
- *
- * @remarks Called with the PDM lock held.  The device lock is NOT take because
- *          that is very likely be a lock order violation.
- */
-typedef DECLCALLBACK(uint32_t) FNPCICONFIGREAD(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb);
-/** Pointer to a FNPCICONFIGREAD() function. */
-typedef FNPCICONFIGREAD *PFNPCICONFIGREAD;
-/** Pointer to a PFNPCICONFIGREAD. */
-typedef PFNPCICONFIGREAD *PPFNPCICONFIGREAD;
-
-/**
- * Callback function for writing to the PCI configuration space.
- *
- * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param   Address         The configuration space register address. [0..4096]
- * @param   u32Value        The value that's being written. The number of bits actually used from
- *                          this value is determined by the cb parameter.
- * @param   cb              The register size. [1,2,4]
- *
- * @remarks Called with the PDM lock held.  The device lock is NOT take because
- *          that is very likely be a lock order violation.
- */
-typedef DECLCALLBACK(void) FNPCICONFIGWRITE(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb);
-/** Pointer to a FNPCICONFIGWRITE() function. */
-typedef FNPCICONFIGWRITE *PFNPCICONFIGWRITE;
-/** Pointer to a PFNPCICONFIGWRITE. */
-typedef PFNPCICONFIGWRITE *PPFNPCICONFIGWRITE;
-
 /** Fixed I/O region number for ROM. */
-#define PCI_ROM_SLOT    6
 #define VBOX_PCI_ROM_SLOT    6
 /** Max number of I/O regions. */
-#define PCI_NUM_REGIONS 7
 #define VBOX_PCI_NUM_REGIONS 7
 
-/*
- * Hack to include the PCIDEVICEINT structure at the right place
- * to avoid duplications of FNPCIIOREGIONMAP and PCI_NUM_REGIONS.
- */
-#ifdef PCI_INCLUDE_PRIVATE
-# include "PCIInternal.h"
-#endif
-
-/**
- * PCI Device structure.
- */
-typedef struct PCIDevice
-{
-    /** PCI config space. */
-    uint8_t                 config[256];
-
-    /** Internal data. */
-    union
-    {
-#ifdef PCIDEVICEINT_DECLARED
-        PCIDEVICEINT        s;
-#endif
-        char                padding[328];
-    } Int;
-
-    /** Read only data.
-     * @{
-     */
-    /** PCI device number on the pci bus. */
-    int32_t                 devfn;
-    uint32_t                Alignment0; /**< Alignment. */
-    /** Device name. */
-    R3PTRTYPE(const char *) name;
-    /** Pointer to the device instance which registered the device. */
-    PPDMDEVINSR3            pDevIns;
-    /**  @} */
-} PCIDEVICE;
-
-/** @todo handle extended space access. */
-
-DECLINLINE(void)     PCIDevSetByte(PPCIDEVICE pPciDev, uint32_t offReg, uint8_t u8Value)
-{
-    pPciDev->config[offReg] = u8Value;
-}
-
-DECLINLINE(uint8_t)  PCIDevGetByte(PPCIDEVICE pPciDev, uint32_t offReg)
-{
-    return pPciDev->config[offReg];
-}
-
-DECLINLINE(void)     PCIDevSetWord(PPCIDEVICE pPciDev, uint32_t offReg, uint16_t u16Value)
-{
-    *(uint16_t*)&pPciDev->config[offReg] = RT_H2LE_U16(u16Value);
-}
-
-DECLINLINE(uint16_t) PCIDevGetWord(PPCIDEVICE pPciDev, uint32_t offReg)
-{
-    uint16_t u16Value = *(uint16_t*)&pPciDev->config[offReg];
-    return RT_H2LE_U16(u16Value);
-}
-
-DECLINLINE(void)     PCIDevSetDWord(PPCIDEVICE pPciDev, uint32_t offReg, uint32_t u32Value)
-{
-    *(uint32_t*)&pPciDev->config[offReg] = RT_H2LE_U32(u32Value);
-}
-
-DECLINLINE(uint32_t) PCIDevGetDWord(PPCIDEVICE pPciDev, uint32_t offReg)
-{
-    uint32_t u32Value = *(uint32_t*)&pPciDev->config[offReg];
-    return RT_H2LE_U32(u32Value);
-}
-
-DECLINLINE(void)     PCIDevSetQWord(PPCIDEVICE pPciDev, uint32_t offReg, uint64_t u64Value)
-{
-    *(uint64_t*)&pPciDev->config[offReg] = RT_H2LE_U64(u64Value);
-}
-
-DECLINLINE(uint64_t) PCIDevGetQWord(PPCIDEVICE pPciDev, uint32_t offReg)
-{
-    uint64_t u64Value = *(uint64_t*)&pPciDev->config[offReg];
-    return RT_H2LE_U64(u64Value);
-}
-
-/**
- * Sets the vendor id config register.
- * @param   pPciDev         The PCI device.
- * @param   u16VendorId     The vendor id.
- */
-DECLINLINE(void) PCIDevSetVendorId(PPCIDEVICE pPciDev, uint16_t u16VendorId)
-{
-    PCIDevSetWord(pPciDev, VBOX_PCI_VENDOR_ID, u16VendorId);
-}
-
-/**
- * Gets the vendor id config register.
- * @returns the vendor id.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint16_t) PCIDevGetVendorId(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID);
-}
-
-
-/**
- * Sets the device id config register.
- * @param   pPciDev         The PCI device.
- * @param   u16DeviceId     The device id.
- */
-DECLINLINE(void) PCIDevSetDeviceId(PPCIDEVICE pPciDev, uint16_t u16DeviceId)
-{
-    PCIDevSetWord(pPciDev, VBOX_PCI_DEVICE_ID, u16DeviceId);
-}
-
-/**
- * Gets the device id config register.
- * @returns the device id.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint16_t) PCIDevGetDeviceId(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID);
-}
-
-/**
- * Sets the command config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u16Command      The command register value.
- */
-DECLINLINE(void) PCIDevSetCommand(PPCIDEVICE pPciDev, uint16_t u16Command)
-{
-    PCIDevSetWord(pPciDev, VBOX_PCI_COMMAND, u16Command);
-}
-
-
-/**
- * Gets the command config register.
- * @returns The command register value.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint16_t) PCIDevGetCommand(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetWord(pPciDev, VBOX_PCI_COMMAND);
-}
-
-/**
- * Checks if the given PCI device is a bus master.
- * @returns true if the device is a bus master, false if not.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(bool) PCIDevIsBusmaster(PPCIDEVICE pPciDev)
-{
-    return (PCIDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_MASTER) != 0;
-}
-
-/**
- * Checks if INTx interrupts disabled in the command config register.
- * @returns true if disabled.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(bool) PCIDevIsIntxDisabled(PPCIDEVICE pPciDev)
-{
-    return (PCIDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_INTX_DISABLE) != 0;
-}
-
-/**
- * Gets the status config register.
- *
- * @returns status config register.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint16_t) PCIDevGetStatus(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetWord(pPciDev, VBOX_PCI_STATUS);
-}
-
-/**
- * Sets the status config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u16Status       The status register value.
- */
-DECLINLINE(void) PCIDevSetStatus(PPCIDEVICE pPciDev, uint16_t u16Status)
-{
-    PCIDevSetWord(pPciDev, VBOX_PCI_STATUS, u16Status);
-}
-
-
-/**
- * Sets the revision id config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8RevisionId    The revision id.
- */
-DECLINLINE(void) PCIDevSetRevisionId(PPCIDEVICE pPciDev, uint8_t u8RevisionId)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_REVISION_ID, u8RevisionId);
-}
-
-
-/**
- * Sets the register level programming class config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8ClassProg     The new value.
- */
-DECLINLINE(void) PCIDevSetClassProg(PPCIDEVICE pPciDev, uint8_t u8ClassProg)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_CLASS_PROG, u8ClassProg);
-}
-
-
-/**
- * Sets the sub-class (aka device class) config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8SubClass      The sub-class.
- */
-DECLINLINE(void) PCIDevSetClassSub(PPCIDEVICE pPciDev, uint8_t u8SubClass)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_CLASS_SUB, u8SubClass);
-}
-
-
-/**
- * Sets the base class config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8BaseClass     The base class.
- */
-DECLINLINE(void) PCIDevSetClassBase(PPCIDEVICE pPciDev, uint8_t u8BaseClass)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_CLASS_BASE, u8BaseClass);
-}
-
-/**
- * Sets the header type config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8HdrType       The header type.
- */
-DECLINLINE(void) PCIDevSetHeaderType(PPCIDEVICE pPciDev, uint8_t u8HdrType)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_HEADER_TYPE, u8HdrType);
-}
-
-/**
- * Gets the header type config register.
- *
- * @param   pPciDev         The PCI device.
- * @returns u8HdrType       The header type.
- */
-DECLINLINE(uint8_t) PCIDevGetHeaderType(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetByte(pPciDev, VBOX_PCI_HEADER_TYPE);
-}
-
-/**
- * Sets the BIST (built-in self-test) config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8Bist          The BIST value.
- */
-DECLINLINE(void) PCIDevSetBIST(PPCIDEVICE pPciDev, uint8_t u8Bist)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_BIST, u8Bist);
-}
-
-/**
- * Gets the BIST (built-in self-test) config register.
- *
- * @param   pPciDev         The PCI device.
- * @returns u8Bist          The BIST.
- */
-DECLINLINE(uint8_t) PCIDevGetBIST(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetByte(pPciDev, VBOX_PCI_BIST);
-}
-
-
-/**
- * Sets a base address config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   iReg            Base address register number (0..5).
- * @param   fIOSpace        Whether it's I/O (true) or memory (false) space.
- * @param   fPrefetchable   Whether the memory is prefetachable. Must be false if fIOSpace == true.
- * @param   f64Bit          Whether the memory can be mapped anywhere in the 64-bit address space. Otherwise restrict to 32-bit.
- * @param   u32Addr         The address value.
- */
-DECLINLINE(void) PCIDevSetBaseAddress(PPCIDEVICE pPciDev, uint8_t iReg, bool fIOSpace, bool fPrefetchable, bool f64Bit,
-                                      uint32_t u32Addr)
-{
-    if (fIOSpace)
-    {
-        Assert(!(u32Addr & 0x3)); Assert(!fPrefetchable); Assert(!f64Bit);
-        u32Addr |= RT_BIT_32(0);
-    }
-    else
-    {
-        Assert(!(u32Addr & 0xf));
-        if (fPrefetchable)
-            u32Addr |= RT_BIT_32(3);
-        if (f64Bit)
-            u32Addr |= 0x2 << 1;
-    }
-    switch (iReg)
-    {
-        case 0: iReg = VBOX_PCI_BASE_ADDRESS_0; break;
-        case 1: iReg = VBOX_PCI_BASE_ADDRESS_1; break;
-        case 2: iReg = VBOX_PCI_BASE_ADDRESS_2; break;
-        case 3: iReg = VBOX_PCI_BASE_ADDRESS_3; break;
-        case 4: iReg = VBOX_PCI_BASE_ADDRESS_4; break;
-        case 5: iReg = VBOX_PCI_BASE_ADDRESS_5; break;
-        default: AssertFailedReturnVoid();
-    }
-
-    PCIDevSetDWord(pPciDev, iReg, u32Addr);
-}
-
-/**
- * Please document me. I don't seem to be getting as much as calculating
- * the address of some PCI region.
- */
-DECLINLINE(uint32_t) PCIDevGetRegionReg(uint32_t iRegion)
-{
-    return iRegion == VBOX_PCI_ROM_SLOT
-         ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
-}
-
-/**
- * Sets the sub-system vendor id config register.
- *
- * @param   pPciDev             The PCI device.
- * @param   u16SubSysVendorId   The sub-system vendor id.
- */
-DECLINLINE(void) PCIDevSetSubSystemVendorId(PPCIDEVICE pPciDev, uint16_t u16SubSysVendorId)
-{
-    PCIDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, u16SubSysVendorId);
-}
-
-/**
- * Gets the sub-system vendor id config register.
- * @returns the sub-system vendor id.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint16_t) PCIDevGetSubSystemVendorId(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID);
-}
-
-
-/**
- * Sets the sub-system id config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u16SubSystemId  The sub-system id.
- */
-DECLINLINE(void) PCIDevSetSubSystemId(PPCIDEVICE pPciDev, uint16_t u16SubSystemId)
-{
-    PCIDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID, u16SubSystemId);
-}
-
-/**
- * Gets the sub-system id config register.
- * @returns the sub-system id.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint16_t) PCIDevGetSubSystemId(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID);
-}
-
-/**
- * Sets offset to capability list.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8Offset        The offset to capability list.
- */
-DECLINLINE(void) PCIDevSetCapabilityList(PPCIDEVICE pPciDev, uint8_t u8Offset)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset);
-}
-
-/**
- * Returns offset to capability list.
- *
- * @returns offset to capability list.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint8_t) PCIDevGetCapabilityList(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST);
-}
-
-/**
- * Sets the interrupt line config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8Line          The interrupt line.
- */
-DECLINLINE(void) PCIDevSetInterruptLine(PPCIDEVICE pPciDev, uint8_t u8Line)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE, u8Line);
-}
-
-/**
- * Gets the interrupt line config register.
- *
- * @returns The interrupt line.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint8_t) PCIDevGetInterruptLine(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE);
-}
-
-/**
- * Sets the interrupt pin config register.
- *
- * @param   pPciDev         The PCI device.
- * @param   u8Pin           The interrupt pin.
- */
-DECLINLINE(void) PCIDevSetInterruptPin(PPCIDEVICE pPciDev, uint8_t u8Pin)
-{
-    PCIDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN, u8Pin);
-}
-
-/**
- * Gets the interrupt pin config register.
- *
- * @returns The interrupt pin.
- * @param   pPciDev         The PCI device.
- */
-DECLINLINE(uint8_t) PCIDevGetInterruptPin(PPCIDEVICE pPciDev)
-{
-    return PCIDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN);
-}
+#define PCI_ROM_SLOT         VBOX_PCI_ROM_SLOT    /**< deprecated */
+#define PCI_NUM_REGIONS      VBOX_PCI_NUM_REGIONS /**< deprecated */
 
-#ifdef PCIDEVICEINT_DECLARED
-DECLINLINE(void) pciDevSetRequestedDevfunc(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_REQUESTED_DEVFUNC;
-}
+/** Number of functions per device. */
+#define VBOX_PCI_MAX_FUNCTIONS      8
+/** Number of devices per bus. */
+#define VBOX_PCI_MAX_DEVICES        32
+/** The device number shift count for a device+function number. */
+#define VBOX_PCI_DEVFN_DEV_SHIFT    3
+/** The device number shift count for a device+function number. */
+#define VBOX_PCI_DEVFN_FUN_MASK     0x7
+/** Make a device+function number.   */
+#define VBOX_PCI_DEVFN_MAKE(a_uPciDevNo, a_uPciFunNo) (((a_uPciDevNo) << VBOX_PCI_DEVFN_DEV_SHIFT) | (a_uPciFunNo))
 
-DECLINLINE(void) pciDevClearRequestedDevfunc(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_REQUESTED_DEVFUNC;
-}
-
-DECLINLINE(bool) pciDevIsRequestedDevfunc(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_REQUESTED_DEVFUNC) != 0;
-}
-
-DECLINLINE(void) pciDevSetPci2PciBridge(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_PCI_TO_PCI_BRIDGE;
-}
-
-DECLINLINE(bool) pciDevIsPci2PciBridge(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_PCI_TO_PCI_BRIDGE) != 0;
-}
-
-DECLINLINE(void) pciDevSetPciExpress(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_PCI_EXPRESS_DEVICE;
-}
-
-DECLINLINE(bool) pciDevIsPciExpress(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_PCI_EXPRESS_DEVICE) != 0;
-}
-
-DECLINLINE(void) pciDevSetMsiCapable(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_MSI_CAPABLE;
-}
-
-DECLINLINE(void) pciDevClearMsiCapable(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_MSI_CAPABLE;
-}
-
-DECLINLINE(bool) pciDevIsMsiCapable(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_MSI_CAPABLE) != 0;
-}
-
-DECLINLINE(void) pciDevSetMsi64Capable(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_MSI64_CAPABLE;
-}
-
-DECLINLINE(void) pciDevClearMsi64Capable(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_MSI64_CAPABLE;
-}
-
-DECLINLINE(bool) pciDevIsMsi64Capable(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_MSI64_CAPABLE) != 0;
-}
-
-DECLINLINE(void) pciDevSetMsixCapable(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_MSIX_CAPABLE;
-}
-
-DECLINLINE(void) pciDevClearMsixCapable(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_MSIX_CAPABLE;
-}
-
-DECLINLINE(bool) pciDevIsMsixCapable(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_MSIX_CAPABLE) != 0;
-}
-
-DECLINLINE(void) pciDevSetPassthrough(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags |= PCIDEV_FLAG_PASSTHROUGH;
-}
-
-DECLINLINE(void) pciDevClearPassthrough(PPCIDEVICE pDev)
-{
-    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_PASSTHROUGH;
-}
-
-DECLINLINE(bool) pciDevIsPassthrough(PPCIDEVICE pDev)
-{
-    return (pDev->Int.s.fFlags & PCIDEV_FLAG_PASSTHROUGH) != 0;
-}
-
-#endif /* PCIDEVICEINT_DECLARED */
 
 #if defined(__cplusplus) && defined(IN_RING3)
 /* For RTStrPrintf(). */
-#include <iprt/string.h>
+# include <iprt/string.h>
 
 /**
  * Class representing PCI address. PCI device consist of
@@ -1180,7 +594,8 @@ struct PCIBusAddress
 
     static const size_t cMaxAddrSize = 10;
 };
-#endif /* __cplusplus */
+
+#endif /* __cplusplus && IN_RING3 */
 
 /** @} */
 
diff --git a/include/VBox/types.h b/include/VBox/types.h
index 493acae..81640ac 100644
--- a/include/VBox/types.h
+++ b/include/VBox/types.h
@@ -340,6 +340,9 @@ typedef R0PTRTYPE(PPDMDEVINS) PPDMDEVINSR0;
 /** RC pointer to a PDM Device Instance. */
 typedef RCPTRTYPE(PPDMDEVINS) PPDMDEVINSRC;
 
+/** Pointer to a PDM PCI device structure. */
+typedef struct PDMPCIDEV *PPDMPCIDEV;
+
 /** Pointer to a PDM USB Device Instance. */
 typedef struct PDMUSBINS *PPDMUSBINS;
 /** Pointer to a pointer to a PDM USB Device Instance. */
diff --git a/include/VBox/vmm/iom.h b/include/VBox/vmm/iom.h
index ec983ed..740064a 100644
--- a/include/VBox/vmm/iom.h
+++ b/include/VBox/vmm/iom.h
@@ -349,6 +349,24 @@ VMMR3_INT_DECL(int)  IOMR3MmioRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS G
                                          RCPTRTYPE(PFNIOMMMIOREAD)  pfnReadCallback,
                                          RCPTRTYPE(PFNIOMMMIOFILL)  pfnFillCallback);
 VMMR3_INT_DECL(int)  IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange);
+VMMR3_INT_DECL(int)  IOMR3MmioExPreRegister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRange,
+                                            uint32_t fFlags, const char *pszDesc,
+                                            RTR3PTR pvUserR3,
+                                            R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR3,
+                                            R3PTRTYPE(PFNIOMMMIOREAD)  pfnReadCallbackR3,
+                                            R3PTRTYPE(PFNIOMMMIOFILL)  pfnFillCallbackR3,
+                                            RTR0PTR pvUserR0,
+                                            R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR0,
+                                            R0PTRTYPE(PFNIOMMMIOREAD)  pfnReadCallbackR0,
+                                            R0PTRTYPE(PFNIOMMMIOFILL)  pfnFillCallbackR0,
+                                            RTRCPTR pvUserRC,
+                                            RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackRC,
+                                            RCPTRTYPE(PFNIOMMMIOREAD)  pfnReadCallbackRC,
+                                            RCPTRTYPE(PFNIOMMMIOFILL)  pfnFillCallbackRC);
+VMMR3_INT_DECL(int)  IOMR3MmioExNotifyMapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys);
+VMMR3_INT_DECL(void) IOMR3MmioExNotifyUnmapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys);
+VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser);
+
 VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict);
 
 VMMR3_INT_DECL(void) IOMR3NotifyBreakpointCountChange(PVM pVM, bool fPortIo, bool fMmio);
diff --git a/include/VBox/vmm/mm.h b/include/VBox/vmm/mm.h
index 2ffe15d..4a638ff 100644
--- a/include/VBox/vmm/mm.h
+++ b/include/VBox/vmm/mm.h
@@ -277,7 +277,7 @@ VMMR3DECL(int)      MMR3HyperRealloc(PVM pVM, void *pv, size_t cb, unsigned uAli
 VMMR3DECL(int)      MMR3HyperSetGuard(PVM pVM, void *pvStart, size_t cb, bool fSet);
 VMMR3DECL(int)      MMR3HyperMapHCPhys(PVM pVM, void *pvR3, RTR0PTR pvR0, RTHCPHYS HCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr);
 VMMR3DECL(int)      MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr);
-VMMR3DECL(int)      MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr);
+VMMR3DECL(int)      MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr);
 VMMR3DECL(int)      MMR3HyperMapPages(PVM pVM, void *pvR3, RTR0PTR pvR0, size_t cPages, PCSUPPAGE paPages, const char *pszDesc, PRTGCPTR pGCPtr);
 VMMR3DECL(int)      MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr);
 VMMR3DECL(RTHCPHYS) MMR3HyperHCVirt2HCPhys(PVM pVM, void *pvHC);
diff --git a/include/VBox/vmm/pdmaudioifs.h b/include/VBox/vmm/pdmaudioifs.h
index 59f2d0c..8b8e2fd 100644
--- a/include/VBox/vmm/pdmaudioifs.h
+++ b/include/VBox/vmm/pdmaudioifs.h
@@ -23,6 +23,10 @@
  * terms and conditions of either the GPL or the CDDL or both.
  */
 
+#ifdef VBOX_WITH_AUDIO_50
+# include "pdmaudioifs_50.h"
+#endif
+
 #ifndef ___VBox_vmm_pdmaudioifs_h
 #define ___VBox_vmm_pdmaudioifs_h
 
diff --git a/include/VBox/vmm/pdmaudioifs_50.h b/include/VBox/vmm/pdmaudioifs_50.h
new file mode 100644
index 0000000..1e5dc98
--- /dev/null
+++ b/include/VBox/vmm/pdmaudioifs_50.h
@@ -0,0 +1,788 @@
+/** @file
+ * PDM - Pluggable Device Manager, audio interfaces.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_vmm_pdmaudioifs_h
+#define ___VBox_vmm_pdmaudioifs_h
+
+#include <VBox/types.h>
+#include <iprt/critsect.h>
+#include <iprt/list.h>
+
+
+/** @defgroup grp_pdm_ifs_audio     PDM Audio Interfaces
+ * @ingroup grp_pdm_interfaces
+ * @{
+ */
+
+/** @todo r=bird: Don't be lazy with documentation! */
+typedef uint32_t PDMAUDIODRVFLAGS;
+
+/** No flags set. */
+/** @todo r=bird: s/PDMAUDIODRVFLAG/PDMAUDIODRV_FLAGS/g */
+#define PDMAUDIODRVFLAG_NONE        0
+/** Marks a primary audio driver which is critical
+ *  when running the VM. */
+#define PDMAUDIODRVFLAG_PRIMARY     RT_BIT(0)
+
+/**
+ * Audio format in signed or unsigned variants.
+ */
+typedef enum PDMAUDIOFMT
+{
+    AUD_FMT_INVALID,
+    AUD_FMT_U8,
+    AUD_FMT_S8,
+    AUD_FMT_U16,
+    AUD_FMT_S16,
+    AUD_FMT_U32,
+    AUD_FMT_S32,
+    /** Hack to blow the type up to 32-bit. */
+    AUD_FMT_32BIT_HACK = 0x7fffffff
+} PDMAUDIOFMT;
+
+/**
+ * Audio configuration of a certain backend.
+ */
+typedef struct PDMAUDIOBACKENDCFG
+{
+    size_t   cbStreamOut;
+    size_t   cbStreamIn;
+    uint32_t cMaxHstStrmsOut;
+    uint32_t cMaxHstStrmsIn;
+} PDMAUDIOBACKENDCFG, *PPDMAUDIOBACKENDCFG;
+
+/**
+ * An audio sample. At the moment stereo (left + right channels) only.
+ * @todo Replace this with a more generic union
+ *       which then also could handle 2.1 or 5.1 sound.
+ */
+typedef struct PDMAUDIOSAMPLE
+{
+    int64_t i64LSample;
+    int64_t i64RSample;
+} PDMAUDIOSAMPLE, *PPDMAUDIOSAMPLE;
+
+typedef enum PDMAUDIOENDIANNESS
+{
+    /** The usual invalid endian. */
+    PDMAUDIOENDIANNESS_INVALID,
+    /** Little endian. */
+    PDMAUDIOENDIANNESS_LITTLE,
+    /** Bit endian. */
+    PDMAUDIOENDIANNESS_BIG,
+    /** Endianness doesn't have a meaning in the context. */
+    PDMAUDIOENDIANNESS_NA,
+    /** The end of the valid endian values (exclusive). */
+    PDMAUDIOENDIANNESS_END,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIOENDIANNESS_32BIT_HACK = 0x7fffffff
+} PDMAUDIOENDIANNESS;
+
+typedef struct PDMAUDIOSTREAMCFG
+{
+    /** Frequency in Hertz (Hz). */
+    uint32_t uHz;
+    /** Number of channels (2 for stereo). */
+    uint8_t cChannels;
+    /** Audio format. */
+    PDMAUDIOFMT enmFormat;
+    /** @todo Use RT_LE2H_*? */
+    PDMAUDIOENDIANNESS enmEndianness;
+} PDMAUDIOSTREAMCFG, *PPDMAUDIOSTREAMCFG;
+
+#if defined(RT_LITTLE_ENDIAN)
+# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_LITTLE
+#elif defined(RT_BIG_ENDIAN)
+# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_BIG
+#else
+# error "Port me!"
+#endif
+
+/**
+ * Audio direction.
+ */
+typedef enum PDMAUDIODIR
+{
+    PDMAUDIODIR_UNKNOWN    = 0,
+    PDMAUDIODIR_IN         = 1,
+    PDMAUDIODIR_OUT        = 2,
+    PDMAUDIODIR_DUPLEX     = 3,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIODIR_32BIT_HACK = 0x7fffffff
+} PDMAUDIODIR;
+
+/**
+ * Audio mixer controls.
+ */
+typedef enum PDMAUDIOMIXERCTL
+{
+    PDMAUDIOMIXERCTL_UNKNOWN = 0,
+    PDMAUDIOMIXERCTL_VOLUME,
+    PDMAUDIOMIXERCTL_PCM,
+    PDMAUDIOMIXERCTL_LINE_IN,
+    PDMAUDIOMIXERCTL_MIC_IN,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff
+} PDMAUDIOMIXERCTL;
+
+/**
+ * Audio recording sources.
+ */
+typedef enum PDMAUDIORECSOURCE
+{
+    PDMAUDIORECSOURCE_UNKNOWN = 0,
+    PDMAUDIORECSOURCE_MIC,
+    PDMAUDIORECSOURCE_CD,
+    PDMAUDIORECSOURCE_VIDEO,
+    PDMAUDIORECSOURCE_AUX,
+    PDMAUDIORECSOURCE_LINE_IN,
+    PDMAUDIORECSOURCE_PHONE,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIORECSOURCE_32BIT_HACK = 0x7fffffff
+} PDMAUDIORECSOURCE;
+
+/**
+ * Audio stream commands. Used in the audio connector
+ * as well as in the actual host backends.
+ */
+typedef enum PDMAUDIOSTREAMCMD
+{
+    /** Unknown command, do not use. */
+    PDMAUDIOSTREAMCMD_UNKNOWN = 0,
+    /** Enables the stream. */
+    PDMAUDIOSTREAMCMD_ENABLE,
+    /** Disables the stream. */
+    PDMAUDIOSTREAMCMD_DISABLE,
+    /** Pauses the stream. */
+    PDMAUDIOSTREAMCMD_PAUSE,
+    /** Resumes the stream. */
+    PDMAUDIOSTREAMCMD_RESUME,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIOSTREAMCMD_32BIT_HACK = 0x7fffffff
+} PDMAUDIOSTREAMCMD;
+
+/**
+ * Properties of audio streams for host/guest
+ * for in or out directions.
+ */
+typedef struct PDMPCMPROPS
+{
+    /** Sample width. Bits per sample. */
+    uint8_t     cBits;
+    /** Signed or unsigned sample. */
+    bool        fSigned;
+    /** Shift count used for faster calculation of various
+     *  values, such as the alignment, bytes to samples and so on.
+     *  Depends on number of stream channels and the stream format
+     *  being used.
+     *
+     ** @todo Use some RTAsmXXX functions instead?
+     */
+    uint8_t     cShift;
+    /** Number of audio channels. */
+    uint8_t     cChannels;
+    /** Alignment mask. */
+    uint32_t    uAlign;
+    /** Sample frequency in Hertz (Hz). */
+    uint32_t    uHz;
+    /** Bandwidth (bytes/s). */
+    uint32_t    cbPerSec;
+    /** Whether the endianness is swapped or not. */
+    bool        fSwapEndian;
+} PDMPCMPROPS, *PPDMPCMPROPS;
+
+/**
+ * Structure keeping an audio volume level.
+ */
+typedef struct PDMAUDIOVOLUME
+{
+    /** Set to @c true if this stream is muted, @c false if not. */
+    bool                   fMuted;
+    /** Left channel volume. */
+    uint32_t               uLeft;
+    /** Right channel volume. */
+    uint32_t               uRight;
+} PDMAUDIOVOLUME, *PPDMAUDIOVOLUME;
+
+/**
+ * Structure for holding rate processing information
+ * of a source + destination audio stream. This is needed
+ * because both streams can differ regarding their rates
+ * and therefore need to be treated accordingly.
+ */
+typedef struct PDMAUDIOSTRMRATE
+{
+    /** Current (absolute) offset in the output
+     *  (destination) stream. */
+    uint64_t       dstOffset;
+    /** Increment for moving dstOffset for the
+     *  destination stream. This is needed because the
+     *  source <-> destination rate might be different. */
+    uint64_t       dstInc;
+    /** Current (absolute) offset in the input
+     *  stream. */
+    uint32_t       srcOffset;
+    /** Last processed sample of the input stream.
+     *  Needed for interpolation. */
+    PDMAUDIOSAMPLE srcSampleLast;
+} PDMAUDIOSTRMRATE, *PPDMAUDIOSTRMRATE;
+
+/**
+ * Note: All internal handling is done in samples,
+ *       not in bytes!
+ */
+typedef uint32_t PDMAUDIOMIXBUFFMT;
+typedef PDMAUDIOMIXBUFFMT *PPDMAUDIOMIXBUFFMT;
+
+typedef struct PDMAUDIOMIXBUF *PPDMAUDIOMIXBUF;
+typedef struct PDMAUDIOMIXBUF
+{
+    RTLISTNODE             Node;
+    /** Name of the buffer. */
+    char                  *pszName;
+    /** Sample buffer. */
+    PPDMAUDIOSAMPLE        pSamples;
+    /** Size of the sample buffer (in samples). */
+    uint32_t               cSamples;
+    /** The current read/write position (in samples)
+     *  in the samples buffer. */
+    uint32_t               offReadWrite;
+    /**
+     * Total samples already mixed down to the parent buffer (if any). Always starting at
+     * the parent's offReadWrite position.
+     *
+     * Note: Count always is specified in parent samples, as the sample count can differ between parent
+     *       and child.
+     */
+    uint32_t               cMixed;
+    uint32_t               cProcessed;
+    /** Pointer to parent buffer (if any). */
+    PPDMAUDIOMIXBUF        pParent;
+    /** List of children mix buffers to keep in sync with (if being a parent buffer). */
+    RTLISTANCHOR           lstBuffers;
+    /** Intermediate structure for buffer conversion tasks. */
+    PPDMAUDIOSTRMRATE      pRate;
+    /** Current volume used for mixing. */
+    PDMAUDIOVOLUME         Volume;
+    /** This buffer's audio format. */
+    PDMAUDIOMIXBUFFMT      AudioFmt;
+    /**
+     * Ratio of the associated parent stream's frequency by this stream's
+     * frequency (1<<32), represented as a signed 64 bit integer.
+     *
+     * For example, if the parent stream has a frequency of 44 khZ, and this
+     * stream has a frequency of 11 kHz, the ration then would be
+     * (44/11 * (1 << 32)).
+     *
+     * Currently this does not get changed once assigned.
+     */
+    int64_t                iFreqRatio;
+    /* For quickly converting samples <-> bytes and
+     * vice versa. */
+    uint8_t                cShift;
+} PDMAUDIOMIXBUF;
+
+/** Stream status flag. To be used with PDMAUDIOSTRMSTS_FLAG_ flags. */
+typedef uint32_t PDMAUDIOSTRMSTS;
+
+/** No flags being set. */
+#define PDMAUDIOSTRMSTS_FLAG_NONE            0
+/** Whether this stream is enabled or disabled. */
+#define PDMAUDIOSTRMSTS_FLAG_ENABLED         RT_BIT_32(0)
+/** Whether this stream has been paused or not. This also implies
+ *  that this is an enabled stream! */
+#define PDMAUDIOSTRMSTS_FLAG_PAUSED          RT_BIT_32(1)
+/** Whether this stream was marked as being disabled
+ *  but there are still associated guest output streams
+ *  which rely on its data. */
+#define PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE RT_BIT_32(2)
+/** Validation mask. */
+#define PDMAUDIOSTRMSTS_VALID_MASK           UINT32_C(0x00000007)
+
+/**
+ * Represents an audio input on the host of a certain
+ * backend (e.g. DirectSound, PulseAudio etc).
+ *
+ * One host audio input is assigned to exactly one parent
+ * guest input stream.
+ */
+struct PDMAUDIOGSTSTRMIN;
+typedef PDMAUDIOGSTSTRMIN *PPDMAUDIOGSTSTRMIN;
+
+typedef struct PDMAUDIOHSTSTRMIN
+{
+    /** List node. */
+    RTLISTNODE             Node;
+    /** PCM properties. */
+    PDMPCMPROPS            Props;
+    /** Stream status flag. */
+    PDMAUDIOSTRMSTS        fStatus;
+    /** Critical section for serializing access. */
+    RTCRITSECT             CritSect;
+    /** This stream's mixing buffer. */
+    PDMAUDIOMIXBUF         MixBuf;
+    /** Pointer to (parent) guest stream. */
+    PPDMAUDIOGSTSTRMIN     pGstStrmIn;
+} PDMAUDIOHSTSTRMIN, *PPDMAUDIOHSTSTRMIN;
+
+/*
+ * Represents an audio output on the host through a certain
+ * backend (e.g. DirectSound, PulseAudio etc).
+ *
+ * One host audio output can have multiple (1:N) guest outputs
+ * assigned.
+ */
+typedef struct PDMAUDIOHSTSTRMOUT
+{
+    /** List node. */
+    RTLISTNODE             Node;
+    /** Stream properites. */
+    PDMPCMPROPS            Props;
+    /** Stream status flag. */
+    PDMAUDIOSTRMSTS        fStatus;
+    /** Critical section for serializing access. */
+    RTCRITSECT             CritSect;
+    /** This stream's mixing buffer. */
+    PDMAUDIOMIXBUF         MixBuf;
+    /** Associated guest output streams. */
+    RTLISTANCHOR           lstGstStrmOut;
+} PDMAUDIOHSTSTRMOUT, *PPDMAUDIOHSTSTRMOUT;
+
+/**
+ * Guest audio stream state.
+ */
+typedef struct PDMAUDIOGSTSTRMSTATE
+{
+    /** Guest audio out stream active or not. */
+    bool                   fActive;
+    /** Guest audio output stream has some samples or not. */
+    bool                   fEmpty;
+    /** Name of this stream. */
+    char                  *pszName;
+    /** Number of references to this stream. Only can be
+     *  destroyed if the reference count is reaching 0. */
+    uint8_t                cRefs;
+} PDMAUDIOGSTSTRMSTATE, *PPDMAUDIOGSTSTRMSTATE;
+
+/**
+ * Represents an audio input from the guest (that is, from the
+ * emulated device, e.g. Intel HDA).
+ *
+ * Each guest input can have multiple host input streams.
+ */
+typedef struct PDMAUDIOGSTSTRMIN
+{
+    /** Guest stream properites. */
+    PDMPCMPROPS            Props;
+    /** Current stream state. */
+    PDMAUDIOGSTSTRMSTATE   State;
+    /** This stream's mixing buffer. */
+    PDMAUDIOMIXBUF         MixBuf;
+    /** Pointer to associated host input stream. */
+    PPDMAUDIOHSTSTRMIN     pHstStrmIn;
+} PDMAUDIOGSTSTRMIN, *PPDMAUDIOGSTSTRMIN;
+
+/**
+ * Represents an audio output from the guest (that is, from the
+ * emulated device, e.g. Intel HDA).
+ *
+ * Each guest output is assigned to a single host output.
+ */
+typedef struct PDMAUDIOGSTSTRMOUT
+{
+    /** List node. */
+    RTLISTNODE             Node;
+    /** Guest output stream properites. */
+    PDMPCMPROPS            Props;
+    /** Current stream state. */
+    PDMAUDIOGSTSTRMSTATE   State;
+    /** This stream's mixing buffer. */
+    PDMAUDIOMIXBUF         MixBuf;
+    /** Pointer to the associated host output stream. */
+    PPDMAUDIOHSTSTRMOUT    pHstStrmOut;
+} PDMAUDIOGSTSTRMOUT, *PPDMAUDIOGSTSTRMOUT;
+
+/** Pointer to a audio connector interface. */
+typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR;
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+/**
+ * Audio callback types. These are all kept generic as those
+ * are used by all device emulations across all backends.
+ */
+typedef enum PDMAUDIOCALLBACKTYPE
+{
+    PDMAUDIOCALLBACKTYPE_GENERIC = 0,
+    PDMAUDIOCALLBACKTYPE_INPUT,
+    PDMAUDIOCALLBACKTYPE_OUTPUT
+} PDMAUDIOCALLBACKTYPE;
+
+/**
+ * Callback data for audio input.
+ */
+typedef struct PDMAUDIOCALLBACKDATAIN
+{
+    /** Input: How many bytes are availabe as input for passing
+     *         to the device emulation. */
+    uint32_t cbInAvail;
+    /** Output: How many bytes have been read. */
+    uint32_t cbOutRead;
+} PDMAUDIOCALLBACKDATAIN, *PPDMAUDIOCALLBACKDATAIN;
+
+/**
+ * Callback data for audio output.
+ */
+typedef struct PDMAUDIOCALLBACKDATAOUT
+{
+    /** Input:  How many bytes are free for the device emulation to write. */
+    uint32_t cbInFree;
+    /** Output: How many bytes were written by the device emulation. */
+    uint32_t cbOutWritten;
+} PDMAUDIOCALLBACKDATAOUT, *PPDMAUDIOCALLBACKDATAOUT;
+
+/**
+ * Structure for keeping an audio callback.
+ */
+typedef struct PDMAUDIOCALLBACK
+{
+    RTLISTANCHOR          Node;
+    PDMAUDIOCALLBACKTYPE  enmType;
+    void                 *pvCtx;
+    size_t                cbCtx;
+    DECLR3CALLBACKMEMBER(int, pfnCallback, (PDMAUDIOCALLBACKTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser));
+} PDMAUDIOCALLBACK, *PPDMAUDIOCALLBACK;
+#endif
+
+/**
+ * Audio connector interface (up).
+ */
+typedef struct PDMIAUDIOCONNECTOR
+{
+    DECLR3CALLBACKMEMBER(int, pfnQueryStatus, (PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbAvailIn, uint32_t *pcbFreeOut, uint32_t *pcSamplesLive));
+
+    /**
+     * Reads PCM audio data from the host (input).
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmIn      Pointer to guest input stream to write to.
+     * @param   pvBuf           Where to store the read data.
+     * @param   cbBuf           Number of bytes to read.
+     * @param   pcbRead         Bytes of audio data read. Optional.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnRead, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead));
+
+    /**
+     * Writes PCM audio data to the host (output).
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmOut     Pointer to guest output stream to read from.
+     * @param   pvBuf           Audio data to be written.
+     * @param   cbBuf           Number of bytes to be written.
+     * @param   pcbWritten      Bytes of audio data written. Optional.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnWrite, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten));
+
+    /**
+     * Retrieves the current configuration of the host audio backend.
+     *
+     * @returns VBox status code.
+     *
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pCfg            Where to store the host audio backend configuration data.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnGetConfiguration, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg));
+
+    /**
+     * Checks whether a specific guest input stream is active or not.
+     *
+     * @returns Whether the specified stream is active or not.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmIn      Pointer to guest input stream.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsActiveIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
+
+    /**
+     * Checks whether a specific guest output stream is active or not.
+     *
+     * @returns Whether the specified stream is active or not.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmOut     Pointer to guest output stream.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsActiveOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
+
+    /**
+     * Checks whether the specified guest input stream is in a valid (working) state.
+     *
+     * @returns True if a host voice in is available, false if not.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmIn      Pointer to guest input stream to check.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsValidIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
+
+    /**
+     * Checks whether the specified guest output stream is in a valid (working) state.
+     *
+     * @returns True if a host voice out is available, false if not.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmOut     Pointer to guest output stream to check.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsValidOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
+
+    /**
+     * Enables a specific guest output stream and starts the audio device.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmOut     Pointer to guest output stream.
+     * @param   fEnable         Whether to enable or disable the specified output stream.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnEnableOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable));
+
+    /**
+     * Enables a specific guest input stream and starts the audio device.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmIn      Pointer to guest input stream.
+     * @param   fEnable         Whether to enable or disable the specified input stream.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnEnableIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn, bool fEnable));
+
+    /**
+     * Creates a guest input stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface           Pointer to the interface structure containing the called function pointer.
+     * @param   pszName              Name of the audio channel.
+     * @param   enmRecSource         Specifies the type of recording source to be opened.
+     * @param   pCfg                 Pointer to PDMAUDIOSTREAMCFG to use.
+     * @param   ppGstStrmIn          Pointer where to return the guest guest input stream on success.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnCreateIn, (PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+                                            PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
+                                            PPDMAUDIOGSTSTRMIN *ppGstStrmIn));
+    /**
+     * Creates a guest output stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface           Pointer to the interface structure containing the called function pointer.
+     * @param   pszName              Name of the audio channel.
+     * @param   pCfg                 Pointer to PDMAUDIOSTREAMCFG to use.
+     * @param   ppGstStrmOut         Pointer where to return the guest guest input stream on success.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnCreateOut, (PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+                                             PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut));
+
+    /**
+     * Destroys a guest input stream.
+     *
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmIn      Pointer to guest input stream.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnDestroyIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
+
+    /**
+     * Destroys a guest output stream.
+     *
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pGstStrmOut     Pointer to guest output stream.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnDestroyOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
+
+    /**
+     * Plays (transfers) all available samples via the connected host backend.
+     *
+     * @returns VBox status code.
+     * @param   pInterface           Pointer to the interface structure containing the called function pointer.
+     * @param   pcSamplesPlayed      Number of samples played. Optional.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPlayOut, (PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed));
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    DECLR3CALLBACKMEMBER(int, pfnRegisterCallbacks, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOCALLBACK paCallbacks, size_t cCallbacks));
+    DECLR3CALLBACKMEMBER(int, pfnCallback, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCALLBACKTYPE enmType, void *pvUser, size_t cbUser));
+#endif
+
+} PDMIAUDIOCONNECTOR;
+
+/** PDMIAUDIOCONNECTOR interface ID. */
+#define PDMIAUDIOCONNECTOR_IID                  "8f8ca10e-9039-423c-9a77-0014aaa98626"
+
+
+/**
+ * Assigns all needed interface callbacks for an audio backend.
+ *
+ * @param   a_NamePrefix        The function name prefix.
+ */
+#define PDMAUDIO_IHOSTAUDIO_CALLBACKS(a_NamePrefix) \
+    do { \
+        pThis->IHostAudio.pfnInit       = RT_CONCAT(a_NamePrefix,Init); \
+        pThis->IHostAudio.pfnShutdown   = RT_CONCAT(a_NamePrefix,Shutdown); \
+        pThis->IHostAudio.pfnInitIn     = RT_CONCAT(a_NamePrefix,InitIn); \
+        pThis->IHostAudio.pfnInitOut    = RT_CONCAT(a_NamePrefix,InitOut); \
+        pThis->IHostAudio.pfnControlOut = RT_CONCAT(a_NamePrefix,ControlOut); \
+        pThis->IHostAudio.pfnControlIn  = RT_CONCAT(a_NamePrefix,ControlIn); \
+        pThis->IHostAudio.pfnFiniIn     = RT_CONCAT(a_NamePrefix,FiniIn); \
+        pThis->IHostAudio.pfnFiniOut    = RT_CONCAT(a_NamePrefix,FiniOut); \
+        pThis->IHostAudio.pfnIsEnabled  = RT_CONCAT(a_NamePrefix,IsEnabled); \
+        pThis->IHostAudio.pfnPlayOut    = RT_CONCAT(a_NamePrefix,PlayOut); \
+        pThis->IHostAudio.pfnCaptureIn  = RT_CONCAT(a_NamePrefix,CaptureIn); \
+        pThis->IHostAudio.pfnGetConf    = RT_CONCAT(a_NamePrefix,GetConf); \
+    } while (0)
+
+/** Pointer to a host audio interface. */
+typedef struct PDMIHOSTAUDIO *PPDMIHOSTAUDIO;
+/**
+ * PDM host audio interface.
+ */
+typedef struct PDMIHOSTAUDIO
+{
+    /**
+     * Initialize the host-specific audio device.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnInit, (PPDMIHOSTAUDIO pInterface));
+
+    /**
+     * Shuts down the host-specific audio device.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnShutdown, (PPDMIHOSTAUDIO pInterface));
+
+    /**
+     * Initialize the host-specific audio device for input stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmIn          Pointer to host input stream.
+     * @param   pCfgReq             Pointer to requested stream configuration.
+     * @param   pCfgAcq             Pointer to acquired stream configuration.
+     * @param   enmRecSource        Specifies the type of recording source to be initialized.
+     * @param   pcSamples           Returns how many samples the backend can handle. Optional.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnInitIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples));
+
+    /**
+     * Initialize the host-specific output device for output stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmOut         Pointer to host output stream.
+     * @param   pCfgReq             Pointer to requested stream configuration.
+     * @param   pCfgAcq             Pointer to acquired stream configuration.
+     * @param   pcSamples           Returns how many samples the backend can handle. Optional.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnInitOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, uint32_t *pcSamples));
+
+    /**
+     * Control the host audio device for an input stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmOut         Pointer to host output stream.
+     * @param   enmStreamCmd        The stream command to issue.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnControlOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd));
+
+    /**
+     * Control the host audio device for an output stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmOut         Pointer to host output stream.
+     * @param   enmStreamCmd        The stream command to issue.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnControlIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd));
+
+    /**
+     * Ends the host audio input streamm.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmIn          Pointer to host input stream.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnFiniIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn));
+
+    /**
+     * Ends the host output stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmOut         Pointer to host output stream.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnFiniOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut));
+
+    /**
+     * Returns whether the specified audio direction in the backend is enabled or not.
+     *
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   enmDir              Audio direction to check status for.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsEnabled, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir));
+
+    /**
+     * Plays a host audio stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmOut         Pointer to host output stream.
+     * @param   pcSamplesPlayed     Pointer to number of samples captured.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPlayOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, uint32_t *pcSamplesPlayed));
+
+    /**
+     * Records audio to input stream.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pHstStrmIn          Pointer to host input stream.
+     * @param   pcSamplesCaptured   Pointer to number of samples captured.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnCaptureIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, uint32_t *pcSamplesCaptured));
+
+    /**
+     * Gets the configuration from the host audio (backend) driver.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pBackendCfg         Pointer where to store the backend audio configuration to.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnGetConf, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg));
+
+} PDMIHOSTAUDIO;
+
+/** PDMIHOSTAUDIO interface ID. */
+#define PDMIHOSTAUDIO_IID                           "BCECDD48-D5E8-49AE-9C1A-85ED64D88638"
+
+/** @} */
+
+#endif
+
diff --git a/include/VBox/vmm/pdmdev.h b/include/VBox/vmm/pdmdev.h
index 8de1268..1a043bb 100644
--- a/include/VBox/vmm/pdmdev.h
+++ b/include/VBox/vmm/pdmdev.h
@@ -32,6 +32,7 @@
 #include <VBox/vmm/pdmifs.h>
 #include <VBox/vmm/pdmins.h>
 #include <VBox/vmm/pdmcommon.h>
+#include <VBox/vmm/pdmpcidev.h>
 #include <VBox/vmm/iom.h>
 #include <VBox/vmm/tm.h>
 #include <VBox/vmm/ssm.h>
@@ -536,14 +537,17 @@ typedef struct PDMPCIBUSREG
      * @returns VBox status code.
      * @param   pDevIns         Device instance of the PCI Bus.
      * @param   pPciDev         The PCI device structure.
-     *                          Any PCI enabled device must keep this in it's instance data!
-     *                          Fill in the PCI data config before registration, please.
-     * @param   pszName         Pointer to device name (permanent, readonly). For debugging, not unique.
-     * @param   iDev            The device number ((dev << 3) | function) the device should have on the bus.
-     *                          If negative, the pci bus device will assign one.
+     * @param   fFlags          Reserved for future use, PDMPCIDEVREG_F_MBZ.
+     * @param   uPciDevNo       PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific
+     *                          device number (0-31).
+     * @param   uPciFunNo       PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific
+     *                          function number (0-7).
+     * @param   pszName         Device name (static but not unique).
+     *
      * @remarks Caller enters the PDM critical section.
      */
-    DECLR3CALLBACKMEMBER(int, pfnRegisterR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev));
+    DECLR3CALLBACKMEMBER(int, pfnRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
+                                             uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName));
 
     /**
      * Initialize MSI support in a PCI device.
@@ -554,7 +558,7 @@ typedef struct PDMPCIBUSREG
      * @param   pMsiReg         MSI registration structure
      * @remarks Caller enters the PDM critical section.
      */
-    DECLR3CALLBACKMEMBER(int, pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg));
+    DECLR3CALLBACKMEMBER(int, pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg));
 
     /**
      * Registers a I/O region (memory mapped or I/O ports) for a PCI device.
@@ -568,7 +572,7 @@ typedef struct PDMPCIBUSREG
      * @param   pfnCallback     Callback for doing the mapping.
      * @remarks Caller enters the PDM critical section.
      */
-    DECLR3CALLBACKMEMBER(int, pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, RTGCPHYS cbRegion,
+    DECLR3CALLBACKMEMBER(int, pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iRegion, RTGCPHYS cbRegion,
                                                      PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback));
 
     /**
@@ -587,7 +591,7 @@ typedef struct PDMPCIBUSREG
      * @remarks Caller enters the PDM critical section.
      * @thread  EMT
      */
-    DECLR3CALLBACKMEMBER(void, pfnSetConfigCallbacksR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev,
+    DECLR3CALLBACKMEMBER(void, pfnSetConfigCallbacksR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
                                                         PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                                                         PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld));
 
@@ -601,10 +605,11 @@ typedef struct PDMPCIBUSREG
      * @param   uTagSrc         The IRQ tag and source (for tracing).
      * @remarks Caller enters the PDM critical section.
      */
-    DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
+    DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
 
     /**
      * Called to perform the job of the bios.
+     *
      * This is only called for the first PCI Bus - it is expected to
      * service all the PCI buses.
      *
@@ -625,7 +630,7 @@ typedef struct PDMPCIBUSREG
 typedef PDMPCIBUSREG *PPDMPCIBUSREG;
 
 /** Current PDMPCIBUSREG version number. */
-#define PDM_PCIBUSREG_VERSION                   PDM_VERSION_MAKE(0xfffe, 5, 0)
+#define PDM_PCIBUSREG_VERSION                   PDM_VERSION_MAKE(0xfffe, 6, 0)
 
 /**
  * PCI Bus RC helpers.
@@ -807,14 +812,15 @@ typedef struct PDMPCIHLPR3
     DECLR3CALLBACKMEMBER(void,  pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc));
 
     /**
-     * Checks if the given address is an MMIO2 base address or not.
+     * Checks if the given address is an MMIO2 or pre-registered MMIO base address.
      *
      * @returns true/false accordingly.
      * @param   pDevIns         The PCI device instance.
      * @param   pOwner          The owner of the memory, optional.
      * @param   GCPhys          The address to check.
+     * @sa      PGMR3PhysMMIOExIsBase
      */
-    DECLR3CALLBACKMEMBER(bool,  pfnIsMMIO2Base,(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys));
+    DECLR3CALLBACKMEMBER(bool,  pfnIsMMIOExBase,(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys));
 
     /**
      * Gets the address of the RC PCI Bus helpers.
@@ -866,7 +872,7 @@ typedef R3PTRTYPE(PDMPCIHLPR3 *) PPDMPCIHLPR3;
 typedef R3PTRTYPE(const PDMPCIHLPR3 *) PCPDMPCIHLPR3;
 
 /** Current PDMPCIHLPR3 version number. */
-#define PDM_PCIHLPR3_VERSION                    PDM_VERSION_MAKE(0xfffb, 3, 0)
+#define PDM_PCIHLPR3_VERSION                    PDM_VERSION_MAKE(0xfffb, 3, 1)
 
 
 /**
@@ -2328,6 +2334,31 @@ typedef const PDMRTCHLP *PCPDMRTCHLP;
 
 #ifdef IN_RING3
 
+/** @name Special values for PDMDEVHLPR3::pfnPCIRegister parameters.
+ * @{  */
+/** Use the primary device configruation (0). */
+# define PDMPCIDEVREG_CFG_PRIMARY           0
+/** Use the next device configuration number in the sequence (max + 1). */
+# define PDMPCIDEVREG_CFG_NEXT              UINT32_MAX
+/** Same device number as the previous PCI device registered with the PDM device.
+ * This is handy when registering multiple PCI device functions and the device
+ * number is left up to the PCI bus.  In order to facilitate on PDM device
+ * instance for each PCI function, this searches earlier PDM device
+ * instances as well. */
+# define PDMPCIDEVREG_DEV_NO_SAME_AS_PREV   UINT8_C(0xfd)
+/** Use the first unused device number (all functions must be unused). */
+# define PDMPCIDEVREG_DEV_NO_FIRST_UNUSED   UINT8_C(0xfe)
+/** Use the first unused device function. */
+# define PDMPCIDEVREG_FUN_NO_FIRST_UNUSED   UINT8_C(0xff)
+
+/** The device and function numbers are not mandatory, just suggestions. */
+# define PDMPCIDEVREG_F_NOT_MANDATORY_NO    RT_BIT_32(0)
+/** Registering a PCI bridge device. */
+# define PDMPCIDEVREG_F_PCI_BRIDGE          RT_BIT_32(1)
+/** Valid flag mask. */
+# define PDMPCIDEVREG_F_VALID_MASK          UINT32_C(0x00000003)
+/** @}   */
+
 /**
  * PDM Device API.
  */
@@ -2508,6 +2539,8 @@ typedef struct PDMDEVHLPR3
      *
      * @returns VBox status.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if no PCI device association.
      * @param   iRegion             The region number. Use the PCI region number as
      *                              this must be known to the PCI bus device too. If
      *                              it's not associated with the PCI device, then
@@ -2520,50 +2553,106 @@ typedef struct PDMDEVHLPR3
      *                              freed.
      * @thread  EMT.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMMIO2Register,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags,
-                                                void **ppv, const char *pszDesc));
+    DECLR3CALLBACKMEMBER(int, pfnMMIO2Register,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cb,
+                                                uint32_t fFlags, void **ppv, const char *pszDesc));
+
+    /**
+     * Pre-register a Memory Mapped I/O (MMIO) region.
+     *
+     * This API must be used for large PCI MMIO regions, as it handles these much
+     * more efficiently and with greater flexibility when it comes to heap usage.
+     * It is only available during device construction.
+     *
+     * To map and unmap the pre-registered region into and our of guest address
+     * space, use the PDMDevHlpMMIOExMap and PDMDevHlpMMIOExUnmap helpers.
+     *
+     * You may call PDMDevHlpMMIOExDeregister from the destructor to free the region
+     * for reasons of symmetry, but it will be automatically deregistered by PDM
+     * once the destructor returns.
+     *
+     * @returns VBox status.
+     * @param   pDevIns             The device instance to register the MMIO with.
+     * @param   pPciDev             The PCI device to associate the region with, use
+     *                              NULL to not associate it with any device.
+     * @param   iRegion             The PCI region number.  When @a pPciDev is NULL,
+     *                              this is a unique number between 0 and UINT8_MAX.
+     * @param   cbRegion            The size of the range (in bytes).
+     * @param   fFlags              Flags, IOMMMIO_FLAGS_XXX.
+     * @param   pszDesc             Pointer to description string. This must not be freed.
+     * @param   pvUser              Ring-3 user argument.
+     * @param   pfnWrite            Pointer to function which is gonna handle Write operations.
+     * @param   pfnRead             Pointer to function which is gonna handle Read operations.
+     * @param   pfnFill             Pointer to function which is gonna handle Fill/memset operations. (optional)
+     * @param   pvUserR0            Ring-0 user argument. Optional.
+     * @param   pszWriteR0          The name of the ring-0 write handler method. Optional.
+     * @param   pszReadR0           The name of the ring-0 read handler method. Optional.
+     * @param   pszFillR0           The name of the ring-0 fill/memset handler method. Optional.
+     * @param   pvUserRC            Raw-mode context user argument. Optional.  If
+     *                              unsigned value is 0x10000 or higher, it will be
+     *                              automatically relocated with the hypervisor
+     *                              guest mapping.
+     * @param   pszWriteRC          The name of the raw-mode context write handler method. Optional.
+     * @param   pszReadRC           The name of the raw-mode context read handler method. Optional.
+     * @param   pszFillRC           The name of the raw-mode context fill/memset handler method. Optional.
+     * @thread  EMT
+     *
+     * @remarks Caller enters the device critical section prior to invoking the
+     *          registered callback methods.
+     * @sa      PDMDevHlpMMIOExMap, PDMDevHlpMMIOExUnmap, PDMDevHlpMMIOExDeregister,
+     *          PDMDevHlpMMIORegisterEx
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMIOExPreRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion,
+                                                    uint32_t fFlags, const char *pszDesc, RTHCPTR pvUser,
+                                                    PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
+                                                    RTR0PTR pvUserR0, const char *pszWriteR0, const char *pszReadR0, const char *pszFillR0,
+                                                    RTRCPTR pvUserRC, const char *pszWriteRC, const char *pszReadRC, const char *pszFillRC));
 
     /**
-     * Deregisters and frees a MMIO2 region.
+     * Deregisters and frees a MMIO or MMIO2 region.
      *
      * Any physical (and virtual) access handlers registered for the region must
-     * be deregistered before calling this function.
+     * be deregistered before calling this function (MMIO2 only).
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if not associated with any.
      * @param   iRegion             The region number used during registration.
      * @thread  EMT.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMMIO2Deregister,(PPDMDEVINS pDevIns, uint32_t iRegion));
+    DECLR3CALLBACKMEMBER(int, pfnMMIOExDeregister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion));
 
     /**
-     * Maps a MMIO2 region into the physical memory space.
+     * Maps a MMIO or MMIO2 region into the physical memory space.
      *
-     * A MMIO2 range may overlap with base memory if a lot of RAM
-     * is configured for the VM, in which case we'll drop the base
-     * memory pages. Presently we will make no attempt to preserve
-     * anything that happens to be present in the base memory that
-     * is replaced, this is of course incorrect but it's too much
-     * effort.
+     * A MMIO2 range or a pre-registered MMIO range may overlap with base memory if
+     * a lot of RAM is configured for the VM, in  which case we'll drop the base
+     * memory pages.  Presently we will make no attempt to preserve anything that
+     * happens to be present in the base memory that is replaced, this is of course
+     * incorrect but it's too much effort.
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if not associated with any.
      * @param   iRegion             The region number used during registration.
      * @param   GCPhys              The physical address to map it at.
      * @thread  EMT.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMMIO2Map,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys));
+    DECLR3CALLBACKMEMBER(int, pfnMMIOExMap,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys));
 
     /**
-     * Unmaps a MMIO2 region previously mapped using pfnMMIO2Map.
+     * Unmaps a MMIO or MMIO2 region previously mapped using pfnMMIOExMap.
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if not associated with any.
      * @param   iRegion             The region number used during registration.
      * @param   GCPhys              The physical address it's currently mapped at.
      * @thread  EMT.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMMIO2Unmap,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys));
+    DECLR3CALLBACKMEMBER(int, pfnMMIOExUnmap,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys));
 
     /**
      * Maps a portion of an MMIO2 region into the hypervisor region.
@@ -2573,6 +2662,8 @@ typedef struct PDMDEVHLPR3
      *
      * @return VBox status code.
      * @param   pDevIns             The device owning the MMIO2 memory.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if not associated with any.
      * @param   iRegion             The region.
      * @param   off                 The offset into the region. Will be rounded down
      *                              to closest page boundary.
@@ -2581,8 +2672,8 @@ typedef struct PDMDEVHLPR3
      * @param   pszDesc             Mapping description.
      * @param   pRCPtr              Where to store the RC address.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMMHyperMapMMIO2,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
-                                                  const char *pszDesc, PRTRCPTR pRCPtr));
+    DECLR3CALLBACKMEMBER(int, pfnMMHyperMapMMIO2,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off,
+                                                  RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr));
 
     /**
      * Maps a portion of an MMIO2 region into kernel space (host).
@@ -2592,6 +2683,8 @@ typedef struct PDMDEVHLPR3
      *
      * @return VBox status code.
      * @param   pDevIns             The device owning the MMIO2 memory.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if not associated with any.
      * @param   iRegion             The region.
      * @param   off                 The offset into the region. Must be page
      *                              aligned.
@@ -2600,8 +2693,8 @@ typedef struct PDMDEVHLPR3
      * @param   pszDesc             Mapping description.
      * @param   pR0Ptr              Where to store the R0 address.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMMIO2MapKernel,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
-                                                  const char *pszDesc, PRTR0PTR pR0Ptr));
+    DECLR3CALLBACKMEMBER(int, pfnMMIO2MapKernel,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off,
+                                                 RTGCPHYS cb, const char *pszDesc, PRTR0PTR pR0Ptr));
 
     /**
      * Register a ROM (BIOS) region.
@@ -3042,32 +3135,54 @@ typedef struct PDMDEVHLPR3
                                                  const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0));
 
     /**
-     * Registers the device with the default PCI bus.
+     * Registers a PCI device with the default PCI bus.
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
      * @param   pPciDev             The PCI device structure.
-     *                              Any PCI enabled device must keep this in it's instance data!
-     *                              Fill in the PCI data config before registration, please.
-     * @remark  This is the simple interface, a Ex interface will be created if
-     *          more features are needed later.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnPCIRegister,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev));
-
-    /**
-     * Initialize MSI support in a PCI device.
+     *                              This must be kept in the instance data.
+     *                              The PCI configuration must be initialized before registration.
+     * @param   idxDevCfg           The CFGM configuration index to use for this
+     *                              device.
+     *                              Zero indicates the default configuration
+     *                              (PDMPCIDEVREG_CFG_PRIMARY), whereas 1 to 255
+     *                              references subkeys "PciDev1" thru "PciDev255".
+     *                              Pass PDMPCIDEVREG_CFG_NEXT to use the next
+     *                              number in the sequence (last + 1).
+     * @param   fFlags              Reserved for future use, PDMPCIDEVREG_F_MBZ.
+     * @param   uPciDevNo           PDMPCIDEVREG_DEV_NO_FIRST_UNUSED,
+     *                              PDMPCIDEVREG_DEV_NO_SAME_AS_PREV, or a specific
+     *                              device number (0-31).  This will be ignored if
+     *                              the CFGM configuration contains a PCIDeviceNo
+     *                              value.
+     * @param   uPciFunNo           PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific
+     *                              function number (0-7).  This will be ignored if
+     *                              the CFGM configuration contains a PCIFunctionNo
+     *                              value.
+     * @param   pszName             Device name, if NULL PDMDEVREG::szName is used.
+     *                              The pointer is saved, so don't free or changed.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPCIRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t idxDevCfg, uint32_t fFlags,
+                                              uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName));
+
+    /**
+     * Initialize MSI support for the given PCI device.
      *
      * @returns VBox status code.
-     * @param   pDevIns         The device instance.
-     * @param   pMsiReg         MSI registartion structure.
+     * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device.  NULL is an alias for the first
+     *                              one registered.
+     * @param   pMsiReg             MSI registartion structure.
      */
-    DECLR3CALLBACKMEMBER(int, pfnPCIRegisterMsi,(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg));
+    DECLR3CALLBACKMEMBER(int, pfnPCIRegisterMsi,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg));
 
     /**
      * Registers a I/O region (memory mapped or I/O ports) for a PCI device.
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   iRegion             The region number.
      * @param   cbRegion            Size of the region.
      * @param   enmType             PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or PCI_ADDRESS_SPACE_MEM_PREFETCH.
@@ -3075,15 +3190,15 @@ typedef struct PDMDEVHLPR3
      * @remarks The callback will be invoked holding the PDM lock. The device lock
      *          is NOT take because that is very likely be a lock order violation.
      */
-    DECLR3CALLBACKMEMBER(int, pfnPCIIORegionRegister,(PPDMDEVINS pDevIns, int iRegion, RTGCPHYS cbRegion,
+    DECLR3CALLBACKMEMBER(int, pfnPCIIORegionRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion,
                                                       PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback));
 
     /**
      * Register PCI configuration space read/write callbacks.
      *
      * @param   pDevIns             The device instance.
-     * @param   pPciDev             The PCI device structure.
-     *                              If NULL the default PCI device for this device instance is used.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   pfnRead             Pointer to the user defined PCI config read function.
      * @param   ppfnReadOld         Pointer to function pointer which will receive the old (default)
      *                              PCI config read function. This way, user can decide when (and if)
@@ -3097,7 +3212,7 @@ typedef struct PDMDEVHLPR3
      *          is NOT take because that is very likely be a lock order violation.
      * @thread  EMT
      */
-    DECLR3CALLBACKMEMBER(void, pfnPCISetConfigCallbacks,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev,
+    DECLR3CALLBACKMEMBER(void, pfnPCISetConfigCallbacks,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
                                                          PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                                                          PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld));
 
@@ -3107,12 +3222,14 @@ typedef struct PDMDEVHLPR3
      * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe
      *          VERR_EM_MEMORY.  The informational status shall NOT be propagated!
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   GCPhys              Physical address start reading from.
      * @param   pvBuf               Where to put the read bits.
      * @param   cbRead              How many bytes to read.
      * @thread  Any thread, but the call may involve the emulation thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead));
+    DECLR3CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead));
 
     /**
      * Bus master physical memory write.
@@ -3120,33 +3237,39 @@ typedef struct PDMDEVHLPR3
      * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe
      *          VERR_EM_MEMORY.  The informational status shall NOT be propagated!
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   GCPhys              Physical address to write to.
      * @param   pvBuf               What to write.
      * @param   cbWrite             How many bytes to write.
      * @thread  Any thread, but the call may involve the emulation thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite));
+    DECLR3CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite));
 
     /**
-     * Set the IRQ for a PCI device.
+     * Sets the IRQ for the given PCI device.
      *
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   iIrq                IRQ number to set.
      * @param   iLevel              IRQ level. See the PDM_IRQ_LEVEL_* \#defines.
      * @thread  Any thread, but will involve the emulation thread.
      */
-    DECLR3CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+    DECLR3CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel));
 
     /**
-     * Set the IRQ for a PCI device, but don't wait for EMT to process
+     * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process
      * the request when not called from EMT.
      *
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   iIrq                IRQ number to set.
      * @param   iLevel              IRQ level.
      * @thread  Any thread, but will involve the emulation thread.
      */
-    DECLR3CALLBACKMEMBER(void, pfnPCISetIrqNoWait,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+    DECLR3CALLBACKMEMBER(void, pfnPCISetIrqNoWait,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel));
 
     /**
      * Set ISA IRQ for a device.
@@ -3606,7 +3729,6 @@ typedef struct PDMDEVHLPR3
      */
     DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDEVINS pDevIns));
 
-
     /** Space reserved for future members.
      * @{ */
     DECLR3CALLBACKMEMBER(void, pfnReserved1,(void));
@@ -3616,9 +3738,9 @@ typedef struct PDMDEVHLPR3
     DECLR3CALLBACKMEMBER(void, pfnReserved5,(void));
     DECLR3CALLBACKMEMBER(void, pfnReserved6,(void));
     DECLR3CALLBACKMEMBER(void, pfnReserved7,(void));
-    /*DECLR3CALLBACKMEMBER(void, pfnReserved8,(void));
-    DECLR3CALLBACKMEMBER(void, pfnReserved9,(void));*/
-    /*DECLR3CALLBACKMEMBER(void, pfnReserved10,(void));*/
+    DECLR3CALLBACKMEMBER(void, pfnReserved8,(void));
+    DECLR3CALLBACKMEMBER(void, pfnReserved9,(void));
+    DECLR3CALLBACKMEMBER(void, pfnReserved10,(void));
     /** @} */
 
 
@@ -3817,8 +3939,7 @@ typedef R3PTRTYPE(struct PDMDEVHLPR3 *) PPDMDEVHLPR3;
 typedef R3PTRTYPE(const struct PDMDEVHLPR3 *) PCPDMDEVHLPR3;
 
 /** Current PDMDEVHLPR3 version number. */
-/* 5.0 is (18, 0) so the next version for trunk has to be (19, 0)! */
-#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE(0xffe7, 17, 0)
+#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE(0xffe7, 19, 0)
 
 
 /**
@@ -3830,40 +3951,48 @@ typedef struct PDMDEVHLPRC
     uint32_t                    u32Version;
 
     /**
-     * Bus master physical memory read.
+     * Bus master physical memory read from the given PCI device.
      *
      * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe
      *          VERR_EM_MEMORY.  The informational status shall NOT be propagated!
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   GCPhys              Physical address start reading from.
      * @param   pvBuf               Where to put the read bits.
      * @param   cbRead              How many bytes to read.
      * @thread  Any thread, but the call may involve the emulation thread.
      */
-    DECLRCCALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead));
+    DECLRCCALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                              void *pvBuf, size_t cbRead));
 
     /**
-     * Bus master physical memory write.
+     * Bus master physical memory write from the given PCI device.
      *
      * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe
      *          VERR_EM_MEMORY.  The informational status shall NOT be propagated!
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   GCPhys              Physical address to write to.
      * @param   pvBuf               What to write.
      * @param   cbWrite             How many bytes to write.
      * @thread  Any thread, but the call may involve the emulation thread.
      */
-    DECLRCCALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite));
+    DECLRCCALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                               const void *pvBuf, size_t cbWrite));
 
     /**
-     * Set the IRQ for a PCI device.
+     * Set the IRQ for the given PCI device.
      *
      * @param   pDevIns         Device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   iIrq            IRQ number to set.
      * @param   iLevel          IRQ level. See the PDM_IRQ_LEVEL_* \#defines.
      * @thread  Any thread, but will involve the emulation thread.
      */
-    DECLRCCALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+    DECLRCCALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel));
 
     /**
      * Set ISA IRQ for a device.
@@ -4038,6 +4167,20 @@ typedef struct PDMDEVHLPRC
      */
     DECLRCCALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns));
 
+    /** Space reserved for future members.
+     * @{ */
+    DECLRCCALLBACKMEMBER(void, pfnReserved1,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved2,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved3,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved4,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved5,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved6,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved7,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved8,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved9,(void));
+    DECLRCCALLBACKMEMBER(void, pfnReserved10,(void));
+    /** @} */
+
     /** Just a safety precaution. */
     uint32_t                        u32TheEnd;
 } PDMDEVHLPRC;
@@ -4047,7 +4190,7 @@ typedef RCPTRTYPE(struct PDMDEVHLPRC *) PPDMDEVHLPRC;
 typedef RCPTRTYPE(const struct PDMDEVHLPRC *) PCPDMDEVHLPRC;
 
 /** Current PDMDEVHLP version number. */
-#define PDM_DEVHLPRC_VERSION                    PDM_VERSION_MAKE(0xffe6, 4, 1)
+#define PDM_DEVHLPRC_VERSION                    PDM_VERSION_MAKE(0xffe6, 5, 0)
 
 
 /**
@@ -4059,40 +4202,48 @@ typedef struct PDMDEVHLPR0
     uint32_t                    u32Version;
 
     /**
-     * Bus master physical memory read.
+     * Bus master physical memory read from the given PCI device.
      *
      * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe
      *          VERR_EM_MEMORY.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   GCPhys              Physical address start reading from.
      * @param   pvBuf               Where to put the read bits.
      * @param   cbRead              How many bytes to read.
      * @thread  Any thread, but the call may involve the emulation thread.
      */
-    DECLR0CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead));
+    DECLR0CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                              void *pvBuf, size_t cbRead));
 
     /**
-     * Bus master physical memory write.
+     * Bus master physical memory write from the given PCI device.
      *
      * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe
      *          VERR_EM_MEMORY.
      * @param   pDevIns             The device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
      * @param   GCPhys              Physical address to write to.
      * @param   pvBuf               What to write.
      * @param   cbWrite             How many bytes to write.
      * @thread  Any thread, but the call may involve the emulation thread.
      */
-    DECLR0CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite));
+    DECLR0CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                               const void *pvBuf, size_t cbWrite));
 
     /**
-     * Set the IRQ for a PCI device.
+     * Set the IRQ for the given PCI device.
      *
-     * @param   pDevIns         Device instance.
-     * @param   iIrq            IRQ number to set.
-     * @param   iLevel          IRQ level. See the PDM_IRQ_LEVEL_* \#defines.
+     * @param   pDevIns             Device instance.
+     * @param   pPciDev             The PCI device structure.  If NULL the default
+     *                              PCI device for this device instance is used.
+     * @param   iIrq                IRQ number to set.
+     * @param   iLevel              IRQ level. See the PDM_IRQ_LEVEL_* \#defines.
      * @thread  Any thread, but will involve the emulation thread.
      */
-    DECLR0CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+    DECLR0CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel));
 
     /**
      * Set ISA IRQ for a device.
@@ -4275,6 +4426,20 @@ typedef struct PDMDEVHLPR0
      */
     DECLR0CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns));
 
+    /** Space reserved for future members.
+     * @{ */
+    DECLR0CALLBACKMEMBER(void, pfnReserved1,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved2,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved3,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved4,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved5,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved6,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved7,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved8,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved9,(void));
+    DECLR0CALLBACKMEMBER(void, pfnReserved10,(void));
+    /** @} */
+
     /** Just a safety precaution. */
     uint32_t                        u32TheEnd;
 } PDMDEVHLPR0;
@@ -4284,7 +4449,7 @@ typedef R0PTRTYPE(struct PDMDEVHLPR0 *) PPDMDEVHLPR0;
 typedef R0PTRTYPE(const struct PDMDEVHLPR0 *) PCPDMDEVHLPR0;
 
 /** Current PDMDEVHLP version number. */
-#define PDM_DEVHLPR0_VERSION                    PDM_VERSION_MAKE(0xffe5, 4, 1)
+#define PDM_DEVHLPR0_VERSION                    PDM_VERSION_MAKE(0xffe5, 5, 0)
 
 
 
@@ -4637,51 +4802,67 @@ DECLINLINE(int) PDMDevHlpMMIODeregister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart
 /**
  * @copydoc PDMDEVHLPR3::pfnMMIO2Register
  */
-DECLINLINE(int) PDMDevHlpMMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)
+DECLINLINE(int) PDMDevHlpMMIO2Register(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cb,
+                                       uint32_t fFlags, void **ppv, const char *pszDesc)
+{
+    return pDevIns->pHlpR3->pfnMMIO2Register(pDevIns, pPciDev, iRegion, cb, fFlags, ppv, pszDesc);
+}
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExPreRegister
+ */
+DECLINLINE(int) PDMDevHlpMMIOExPreRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion,
+                                           uint32_t fFlags, const char *pszDesc, RTHCPTR pvUser,
+                                           PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
+                                           RTR0PTR pvUserR0, const char *pszWriteR0, const char *pszReadR0, const char *pszFillR0,
+                                           RTRCPTR pvUserRC, const char *pszWriteRC, const char *pszReadRC, const char *pszFillRC)
 {
-    return pDevIns->pHlpR3->pfnMMIO2Register(pDevIns, iRegion, cb, fFlags, ppv, pszDesc);
+    return pDevIns->pHlpR3->pfnMMIOExPreRegister(pDevIns, pPciDev, iRegion, cbRegion, fFlags, pszDesc,
+                                                 pvUser, pfnWrite, pfnRead, pfnFill,
+                                                 pvUserR0, pszWriteR0, pszReadR0, pszFillR0,
+                                                 pvUserRC, pszWriteRC, pszReadRC, pszFillRC);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnMMIO2Deregister
+ * @copydoc PDMDEVHLPR3::pfnMMIOExDeregister
  */
-DECLINLINE(int) PDMDevHlpMMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion)
+DECLINLINE(int) PDMDevHlpMMIOExDeregister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion)
 {
-    return pDevIns->pHlpR3->pfnMMIO2Deregister(pDevIns, iRegion);
+    return pDevIns->pHlpR3->pfnMMIOExDeregister(pDevIns, pPciDev, iRegion);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnMMIO2Map
+ * @copydoc PDMDEVHLPR3::pfnMMIOExMap
  */
-DECLINLINE(int) PDMDevHlpMMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+DECLINLINE(int) PDMDevHlpMMIOExMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys)
 {
-    return pDevIns->pHlpR3->pfnMMIO2Map(pDevIns, iRegion, GCPhys);
+    return pDevIns->pHlpR3->pfnMMIOExMap(pDevIns, pPciDev, iRegion, GCPhys);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnMMIO2Unmap
+ * @copydoc PDMDEVHLPR3::pfnMMIOExUnmap
  */
-DECLINLINE(int) PDMDevHlpMMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+DECLINLINE(int) PDMDevHlpMMIOExUnmap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys)
 {
-    return pDevIns->pHlpR3->pfnMMIO2Unmap(pDevIns, iRegion, GCPhys);
+    return pDevIns->pHlpR3->pfnMMIOExUnmap(pDevIns, pPciDev, iRegion, GCPhys);
 }
 
 /**
  * @copydoc PDMDEVHLPR3::pfnMMHyperMapMMIO2
  */
-DECLINLINE(int) PDMDevHlpMMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+DECLINLINE(int) PDMDevHlpMMHyperMapMMIO2(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
                                          const char *pszDesc, PRTRCPTR pRCPtr)
 {
-    return pDevIns->pHlpR3->pfnMMHyperMapMMIO2(pDevIns, iRegion, off, cb, pszDesc, pRCPtr);
+    return pDevIns->pHlpR3->pfnMMHyperMapMMIO2(pDevIns, pPciDev, iRegion, off, cb, pszDesc, pRCPtr);
 }
 
 /**
  * @copydoc PDMDEVHLPR3::pfnMMIO2MapKernel
  */
-DECLINLINE(int) PDMDevHlpMMIO2MapKernel(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+DECLINLINE(int) PDMDevHlpMMIO2MapKernel(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
                                          const char *pszDesc, PRTR0PTR pR0Ptr)
 {
-    return pDevIns->pHlpR3->pfnMMIO2MapKernel(pDevIns, iRegion, off, cb, pszDesc, pR0Ptr);
+    return pDevIns->pHlpR3->pfnMMIO2MapKernel(pDevIns, pPciDev, iRegion, off, cb, pszDesc, pR0Ptr);
 }
 
 /**
@@ -4989,35 +5170,82 @@ DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) PDMDevHlpSTAMRegisterF(PPDMDEVINS pDe
     va_end(va);
 }
 
+/*
+ * Registers the device with the default PCI bus.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns             The device instance.
+ * @param   pPciDev             The PCI device structure.
+ *                              This must be kept in the instance data.
+ *                              The PCI configuration must be initialized before registration.
+ */
+DECLINLINE(int) PDMDevHlpPCIRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev)
+{
+    return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, PDMPCIDEVREG_CFG_NEXT, 0 /*fFlags*/,
+                                           PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, NULL);
+}
+
 /**
  * @copydoc PDMDEVHLPR3::pfnPCIRegister
  */
-DECLINLINE(int) PDMDevHlpPCIRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev)
+DECLINLINE(int) PDMDevHlpPCIRegisterEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t idxDevCfg, uint32_t fFlags,
+                                       uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
 {
-    return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev);
+    return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, idxDevCfg, fFlags, uPciDevNo, uPciFunNo, pszName);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnPCIIORegionRegister
+ * Registers a I/O region (memory mapped or I/O ports) for the default PCI
+ * device.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns             The device instance.
+ * @param   iRegion             The region number.
+ * @param   cbRegion            Size of the region.
+ * @param   enmType             PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or PCI_ADDRESS_SPACE_MEM_PREFETCH.
+ * @param   pfnCallback         Callback for doing the mapping.
+ * @remarks The callback will be invoked holding the PDM lock. The device lock
+ *          is NOT take because that is very likely be a lock order violation.
  */
 DECLINLINE(int) PDMDevHlpPCIIORegionRegister(PPDMDEVINS pDevIns, int iRegion, RTGCPHYS cbRegion,
                                              PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
 {
-    return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, iRegion, cbRegion, enmType, pfnCallback);
+    return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, pfnCallback);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnPCIRegisterMsi
+ * @copydoc PDMDEVHLPR3::pfnPCIIORegionRegister
+ */
+DECLINLINE(int) PDMDevHlpPCIIORegionRegisterEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iRegion, RTGCPHYS cbRegion,
+                                               PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
+{
+    return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pPciDev, iRegion, cbRegion, enmType, pfnCallback);
+}
+
+/**
+ * Initialize MSI support for the first PCI device.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns             The device instance.
+ * @param   pMsiReg             MSI registartion structure.
  */
 DECLINLINE(int) PDMDevHlpPCIRegisterMsi(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg)
 {
-    return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, pMsiReg);
+    return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, NULL, pMsiReg);
+}
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnPCIRegisterMsi
+ */
+DECLINLINE(int) PDMDevHlpPCIRegisterMsiEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)
+{
+    return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, pPciDev, pMsiReg);
 }
 
 /**
  * @copydoc PDMDEVHLPR3::pfnPCISetConfigCallbacks
  */
-DECLINLINE(void) PDMDevHlpPCISetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev,
+DECLINLINE(void) PDMDevHlpPCISetConfigCallbacks(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
                                                 PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                                                 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
 {
@@ -5027,35 +5255,94 @@ DECLINLINE(void) PDMDevHlpPCISetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE p
 #endif /* IN_RING3 */
 
 /**
- * @copydoc PDMDEVHLPR3::pfnPCIPhysRead
+ * Bus master physical memory read from the default PCI device.
+ *
+ * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe
+ *          VERR_EM_MEMORY.  The informational status shall NOT be propagated!
+ * @param   pDevIns             The device instance.
+ * @param   GCPhys              Physical address start reading from.
+ * @param   pvBuf               Where to put the read bits.
+ * @param   cbRead              How many bytes to read.
+ * @thread  Any thread, but the call may involve the emulation thread.
  */
 DECLINLINE(int) PDMDevHlpPCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
 {
-    return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
+    return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnPCIPhysWrite
+ * @copydoc PDMDEVHLPR3::pfnPCIPhysRead
+ */
+DECLINLINE(int) PDMDevHlpPCIPhysReadEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+    return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead);
+}
+
+/**
+ * Bus master physical memory write from the default PCI device.
+ *
+ * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe
+ *          VERR_EM_MEMORY.  The informational status shall NOT be propagated!
+ * @param   pDevIns             The device instance.
+ * @param   GCPhys              Physical address to write to.
+ * @param   pvBuf               What to write.
+ * @param   cbWrite             How many bytes to write.
+ * @thread  Any thread, but the call may involve the emulation thread.
  */
 DECLINLINE(int) PDMDevHlpPCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
 {
-    return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
+    return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnPCISetIrq
+ * @copydoc PDMDEVHLPR3::pfnPCIPhysWrite
+ */
+DECLINLINE(int) PDMDevHlpPCIPhysWriteEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+{
+    return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite);
+}
+
+/**
+ * Sets the IRQ for the default PCI device.
+ *
+ * @param   pDevIns             The device instance.
+ * @param   iIrq                IRQ number to set.
+ * @param   iLevel              IRQ level. See the PDM_IRQ_LEVEL_* \#defines.
+ * @thread  Any thread, but will involve the emulation thread.
  */
 DECLINLINE(void) PDMDevHlpPCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
 {
-    pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, iIrq, iLevel);
+    pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel);
 }
 
 /**
- * @copydoc PDMDEVHLPR3::pfnPCISetIrqNoWait
+ * @copydoc PDMDEVHLPR3::pfnPCISetIrq
+ */
+DECLINLINE(void) PDMDevHlpPCISetIrqEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
+{
+    pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel);
+}
+
+/**
+ * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process
+ * the request when not called from EMT.
+ *
+ * @param   pDevIns             The device instance.
+ * @param   iIrq                IRQ number to set.
+ * @param   iLevel              IRQ level.
+ * @thread  Any thread, but will involve the emulation thread.
  */
 DECLINLINE(void) PDMDevHlpPCISetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel)
 {
-    pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, iIrq, iLevel);
+    pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel);
+}
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnPCISetIrqNoWait
+ */
+DECLINLINE(void) PDMDevHlpPCISetIrqNoWaitEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
+{
+    pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel);
 }
 
 /**
diff --git a/include/VBox/vmm/pdmpci.h b/include/VBox/vmm/pdmpci.h
index 68f38ed..6c6cb9d 100644
--- a/include/VBox/vmm/pdmpci.h
+++ b/include/VBox/vmm/pdmpci.h
@@ -31,7 +31,7 @@
 
 RT_C_DECLS_BEGIN
 
-/** @defgroup grp_pdm_pcidev    The raw PCI Devices API
+/** @defgroup grp_pdm_pciraw    The raw PCI Devices API
  * @ingroup grp_pdm
  * @{
  */
diff --git a/include/VBox/vmm/pdmpcidev.h b/include/VBox/vmm/pdmpcidev.h
new file mode 100644
index 0000000..3e6282d
--- /dev/null
+++ b/include/VBox/vmm/pdmpcidev.h
@@ -0,0 +1,627 @@
+/** @file
+ * PCI - The PCI Controller And Devices. (DEV)
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_vmm_pdmpcidev_h
+#define ___VBox_vmm_pdmpcidev_h
+
+#include <VBox/pci.h>
+#include <iprt/assert.h>
+
+
+/** @defgroup grp_pdm_pcidev       PDM PCI Device
+ * @ingroup grp_pdm_device
+ * @{
+ */
+
+/**
+ * Callback function for reading from the PCI configuration space.
+ *
+ * @returns The register value.
+ * @param   pDevIns         Pointer to the device instance the PCI device
+ *                          belongs to.
+ * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
+ * @param   Address         The configuration space register address. [0..4096]
+ * @param   cb              The register size. [1,2,4]
+ *
+ * @remarks Called with the PDM lock held.  The device lock is NOT take because
+ *          that is very likely be a lock order violation.
+ *
+ * @todo add pDevIns parameter.
+ */
+typedef DECLCALLBACK(uint32_t) FNPCICONFIGREAD(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t Address, unsigned cb);
+/** Pointer to a FNPCICONFIGREAD() function. */
+typedef FNPCICONFIGREAD *PFNPCICONFIGREAD;
+/** Pointer to a PFNPCICONFIGREAD. */
+typedef PFNPCICONFIGREAD *PPFNPCICONFIGREAD;
+
+/**
+ * Callback function for writing to the PCI configuration space.
+ *
+ * @param   pDevIns         Pointer to the device instance the PCI device
+ *                          belongs to.
+ * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
+ * @param   Address         The configuration space register address. [0..4096]
+ * @param   u32Value        The value that's being written. The number of bits actually used from
+ *                          this value is determined by the cb parameter.
+ * @param   cb              The register size. [1,2,4]
+ *
+ * @remarks Called with the PDM lock held.  The device lock is NOT take because
+ *          that is very likely be a lock order violation.
+ *
+ * @todo add pDevIns parameter and fix iRegion type.
+ */
+typedef DECLCALLBACK(void) FNPCICONFIGWRITE(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb);
+/** Pointer to a FNPCICONFIGWRITE() function. */
+typedef FNPCICONFIGWRITE *PFNPCICONFIGWRITE;
+/** Pointer to a PFNPCICONFIGWRITE. */
+typedef PFNPCICONFIGWRITE *PPFNPCICONFIGWRITE;
+
+/**
+ * Callback function for mapping an PCI I/O region.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns         Pointer to the device instance the PCI device
+ *                          belongs to.
+ * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
+ * @param   iRegion         The region number.
+ * @param   GCPhysAddress   Physical address of the region. If enmType is PCI_ADDRESS_SPACE_IO, this
+ *                          is an I/O port, otherwise it's a physical address.
+ *
+ *                          NIL_RTGCPHYS indicates that a MMIO2 mapping is about to be unmapped and
+ *                          that the device deregister access handlers for it and update its internal
+ *                          state to reflect this.
+ *
+ * @param   cb              Size of the region in bytes.
+ * @param   enmType         One of the PCI_ADDRESS_SPACE_* values.
+ *
+ * @remarks Called with the PDM lock held.  The device lock is NOT take because
+ *          that is very likely be a lock order violation.
+ *
+ * @todo add pDevIns parameter and fix iRegion type.
+ */
+typedef DECLCALLBACK(int) FNPCIIOREGIONMAP(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                           RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType);
+/** Pointer to a FNPCIIOREGIONMAP() function. */
+typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP;
+
+
+/*
+ * Hack to include the PDMPCIDEVINT structure at the right place
+ * to avoid duplications of FNPCIIOREGIONMAP and such.
+ */
+#ifdef PDMPCIDEV_INCLUDE_PRIVATE
+# include "pdmpcidevint.h"
+#endif
+
+/**
+ * PDM PCI Device structure.
+ *
+ * A PCI device belongs to a PDM device.  A PDM device may have zero or more PCI
+ * devices associated with it.  The first PCI device that it registers
+ * automatically becomes the default PCI device and can be used implicitly
+ * with the device helper APIs.  Subsequent PCI devices must be specified
+ * expeclitly to the device helper APIs when used.
+ */
+typedef struct PDMPCIDEV
+{
+    /** PCI config space. */
+    uint8_t                 abConfig[256];
+
+    /** Internal data. */
+    union
+    {
+#ifdef PDMPCIDEVINT_DECLARED
+        PDMPCIDEVINT        s;
+#endif
+        uint8_t             padding[HC_ARCH_BITS == 32 ? 272 : 384];
+    } Int;
+
+    /** @name Read only data.
+     * @{
+     */
+    /** PCI device number [11:3] and function [2:0] on the pci bus.
+     * @sa VBOX_PCI_DEVFN_MAKE, VBOX_PCI_DEVFN_FUN_MASK, VBOX_PCI_DEVFN_DEV_SHIFT */
+    uint32_t                uDevFn;
+    uint32_t                Alignment0; /**< Alignment. */
+    /** Device name. */
+    R3PTRTYPE(const char *) pszNameR3;
+    /** Reserved. */
+    RTR3PTR                 pvReserved;
+    /** @} */
+} PDMPCIDEV;
+#ifdef PDMPCIDEVINT_DECLARED
+AssertCompile(RT_SIZEOFMEMB(PDMPCIDEV, Int.s) <= RT_SIZEOFMEMB(PDMPCIDEV, Int.padding));
+#endif
+
+
+
+/** @name PDM PCI config space accessor function.
+ * @{
+ */
+
+/** @todo handle extended space access. */
+
+DECLINLINE(void)     PDMPciDevSetByte(PPDMPCIDEV pPciDev, uint32_t offReg, uint8_t u8Value)
+{
+    Assert(offReg < sizeof(pPciDev->abConfig));
+    pPciDev->abConfig[offReg] = u8Value;
+}
+
+DECLINLINE(uint8_t)  PDMPciDevGetByte(PPDMPCIDEV pPciDev, uint32_t offReg)
+{
+    Assert(offReg < sizeof(pPciDev->abConfig));
+    return pPciDev->abConfig[offReg];
+}
+
+DECLINLINE(void)     PDMPciDevSetWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint16_t u16Value)
+{
+    Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t));
+    *(uint16_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U16(u16Value);
+}
+
+DECLINLINE(uint16_t) PDMPciDevGetWord(PPDMPCIDEV pPciDev, uint32_t offReg)
+{
+    uint16_t u16Value;
+    Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t));
+    u16Value = *(uint16_t*)&pPciDev->abConfig[offReg];
+    return RT_H2LE_U16(u16Value);
+}
+
+DECLINLINE(void)     PDMPciDevSetDWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint32_t u32Value)
+{
+    Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t));
+    *(uint32_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U32(u32Value);
+}
+
+DECLINLINE(uint32_t) PDMPciDevGetDWord(PPDMPCIDEV pPciDev, uint32_t offReg)
+{
+    uint32_t u32Value;
+    Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t));
+    u32Value = *(uint32_t*)&pPciDev->abConfig[offReg];
+    return RT_H2LE_U32(u32Value);
+}
+
+DECLINLINE(void)     PDMPciDevSetQWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint64_t u64Value)
+{
+    Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t));
+    *(uint64_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U64(u64Value);
+}
+
+DECLINLINE(uint64_t) PDMPciDevGetQWord(PPDMPCIDEV pPciDev, uint32_t offReg)
+{
+    uint64_t u64Value;
+    Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t));
+    u64Value = *(uint64_t*)&pPciDev->abConfig[offReg];
+    return RT_H2LE_U64(u64Value);
+}
+
+/**
+ * Sets the vendor id config register.
+ * @param   pPciDev         The PCI device.
+ * @param   u16VendorId     The vendor id.
+ */
+DECLINLINE(void) PDMPciDevSetVendorId(PPDMPCIDEV pPciDev, uint16_t u16VendorId)
+{
+    PDMPciDevSetWord(pPciDev, VBOX_PCI_VENDOR_ID, u16VendorId);
+}
+
+/**
+ * Gets the vendor id config register.
+ * @returns the vendor id.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint16_t) PDMPciDevGetVendorId(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID);
+}
+
+
+/**
+ * Sets the device id config register.
+ * @param   pPciDev         The PCI device.
+ * @param   u16DeviceId     The device id.
+ */
+DECLINLINE(void) PDMPciDevSetDeviceId(PPDMPCIDEV pPciDev, uint16_t u16DeviceId)
+{
+    PDMPciDevSetWord(pPciDev, VBOX_PCI_DEVICE_ID, u16DeviceId);
+}
+
+/**
+ * Gets the device id config register.
+ * @returns the device id.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint16_t) PDMPciDevGetDeviceId(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID);
+}
+
+/**
+ * Sets the command config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u16Command      The command register value.
+ */
+DECLINLINE(void) PDMPciDevSetCommand(PPDMPCIDEV pPciDev, uint16_t u16Command)
+{
+    PDMPciDevSetWord(pPciDev, VBOX_PCI_COMMAND, u16Command);
+}
+
+
+/**
+ * Gets the command config register.
+ * @returns The command register value.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint16_t) PDMPciDevGetCommand(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND);
+}
+
+/**
+ * Checks if the given PCI device is a bus master.
+ * @returns true if the device is a bus master, false if not.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(bool) PDMPciDevIsBusmaster(PPDMPCIDEV pPciDev)
+{
+    return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_MASTER) != 0;
+}
+
+/**
+ * Checks if INTx interrupts disabled in the command config register.
+ * @returns true if disabled.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(bool) PDMPciDevIsIntxDisabled(PPDMPCIDEV pPciDev)
+{
+    return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_INTX_DISABLE) != 0;
+}
+
+/**
+ * Gets the status config register.
+ *
+ * @returns status config register.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint16_t) PDMPciDevGetStatus(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetWord(pPciDev, VBOX_PCI_STATUS);
+}
+
+/**
+ * Sets the status config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u16Status       The status register value.
+ */
+DECLINLINE(void) PDMPciDevSetStatus(PPDMPCIDEV pPciDev, uint16_t u16Status)
+{
+    PDMPciDevSetWord(pPciDev, VBOX_PCI_STATUS, u16Status);
+}
+
+
+/**
+ * Sets the revision id config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8RevisionId    The revision id.
+ */
+DECLINLINE(void) PDMPciDevSetRevisionId(PPDMPCIDEV pPciDev, uint8_t u8RevisionId)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_REVISION_ID, u8RevisionId);
+}
+
+
+/**
+ * Sets the register level programming class config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8ClassProg     The new value.
+ */
+DECLINLINE(void) PDMPciDevSetClassProg(PPDMPCIDEV pPciDev, uint8_t u8ClassProg)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_PROG, u8ClassProg);
+}
+
+
+/**
+ * Sets the sub-class (aka device class) config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8SubClass      The sub-class.
+ */
+DECLINLINE(void) PDMPciDevSetClassSub(PPDMPCIDEV pPciDev, uint8_t u8SubClass)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_SUB, u8SubClass);
+}
+
+
+/**
+ * Sets the base class config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8BaseClass     The base class.
+ */
+DECLINLINE(void) PDMPciDevSetClassBase(PPDMPCIDEV pPciDev, uint8_t u8BaseClass)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_BASE, u8BaseClass);
+}
+
+/**
+ * Sets the header type config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8HdrType       The header type.
+ */
+DECLINLINE(void) PDMPciDevSetHeaderType(PPDMPCIDEV pPciDev, uint8_t u8HdrType)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_HEADER_TYPE, u8HdrType);
+}
+
+/**
+ * Gets the header type config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @returns u8HdrType       The header type.
+ */
+DECLINLINE(uint8_t) PDMPciDevGetHeaderType(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetByte(pPciDev, VBOX_PCI_HEADER_TYPE);
+}
+
+/**
+ * Sets the BIST (built-in self-test) config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8Bist          The BIST value.
+ */
+DECLINLINE(void) PDMPciDevSetBIST(PPDMPCIDEV pPciDev, uint8_t u8Bist)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_BIST, u8Bist);
+}
+
+/**
+ * Gets the BIST (built-in self-test) config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @returns u8Bist          The BIST.
+ */
+DECLINLINE(uint8_t) PDMPciDevGetBIST(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetByte(pPciDev, VBOX_PCI_BIST);
+}
+
+
+/**
+ * Sets a base address config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   iReg            Base address register number (0..5).
+ * @param   fIOSpace        Whether it's I/O (true) or memory (false) space.
+ * @param   fPrefetchable   Whether the memory is prefetachable. Must be false if fIOSpace == true.
+ * @param   f64Bit          Whether the memory can be mapped anywhere in the 64-bit address space. Otherwise restrict to 32-bit.
+ * @param   u32Addr         The address value.
+ */
+DECLINLINE(void) PDMPciDevSetBaseAddress(PPDMPCIDEV pPciDev, uint8_t iReg, bool fIOSpace, bool fPrefetchable, bool f64Bit,
+                                         uint32_t u32Addr)
+{
+    if (fIOSpace)
+    {
+        Assert(!(u32Addr & 0x3)); Assert(!fPrefetchable); Assert(!f64Bit);
+        u32Addr |= RT_BIT_32(0);
+    }
+    else
+    {
+        Assert(!(u32Addr & 0xf));
+        if (fPrefetchable)
+            u32Addr |= RT_BIT_32(3);
+        if (f64Bit)
+            u32Addr |= 0x2 << 1;
+    }
+    switch (iReg)
+    {
+        case 0: iReg = VBOX_PCI_BASE_ADDRESS_0; break;
+        case 1: iReg = VBOX_PCI_BASE_ADDRESS_1; break;
+        case 2: iReg = VBOX_PCI_BASE_ADDRESS_2; break;
+        case 3: iReg = VBOX_PCI_BASE_ADDRESS_3; break;
+        case 4: iReg = VBOX_PCI_BASE_ADDRESS_4; break;
+        case 5: iReg = VBOX_PCI_BASE_ADDRESS_5; break;
+        default: AssertFailedReturnVoid();
+    }
+
+    PDMPciDevSetDWord(pPciDev, iReg, u32Addr);
+}
+
+/**
+ * Please document me. I don't seem to be getting as much as calculating
+ * the address of some PCI region.
+ */
+DECLINLINE(uint32_t) PDMPciDevGetRegionReg(uint32_t iRegion)
+{
+    return iRegion == VBOX_PCI_ROM_SLOT
+         ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
+}
+
+/**
+ * Sets the sub-system vendor id config register.
+ *
+ * @param   pPciDev             The PCI device.
+ * @param   u16SubSysVendorId   The sub-system vendor id.
+ */
+DECLINLINE(void) PDMPciDevSetSubSystemVendorId(PPDMPCIDEV pPciDev, uint16_t u16SubSysVendorId)
+{
+    PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, u16SubSysVendorId);
+}
+
+/**
+ * Gets the sub-system vendor id config register.
+ * @returns the sub-system vendor id.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint16_t) PDMPciDevGetSubSystemVendorId(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID);
+}
+
+
+/**
+ * Sets the sub-system id config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u16SubSystemId  The sub-system id.
+ */
+DECLINLINE(void) PDMPciDevSetSubSystemId(PPDMPCIDEV pPciDev, uint16_t u16SubSystemId)
+{
+    PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID, u16SubSystemId);
+}
+
+/**
+ * Gets the sub-system id config register.
+ * @returns the sub-system id.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint16_t) PDMPciDevGetSubSystemId(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID);
+}
+
+/**
+ * Sets offset to capability list.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8Offset        The offset to capability list.
+ */
+DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset);
+}
+
+/**
+ * Returns offset to capability list.
+ *
+ * @returns offset to capability list.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST);
+}
+
+/**
+ * Sets the interrupt line config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8Line          The interrupt line.
+ */
+DECLINLINE(void) PDMPciDevSetInterruptLine(PPDMPCIDEV pPciDev, uint8_t u8Line)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE, u8Line);
+}
+
+/**
+ * Gets the interrupt line config register.
+ *
+ * @returns The interrupt line.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint8_t) PDMPciDevGetInterruptLine(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE);
+}
+
+/**
+ * Sets the interrupt pin config register.
+ *
+ * @param   pPciDev         The PCI device.
+ * @param   u8Pin           The interrupt pin.
+ */
+DECLINLINE(void) PDMPciDevSetInterruptPin(PPDMPCIDEV pPciDev, uint8_t u8Pin)
+{
+    PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN, u8Pin);
+}
+
+/**
+ * Gets the interrupt pin config register.
+ *
+ * @returns The interrupt pin.
+ * @param   pPciDev         The PCI device.
+ */
+DECLINLINE(uint8_t) PDMPciDevGetInterruptPin(PPDMPCIDEV pPciDev)
+{
+    return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN);
+}
+
+/** @} */
+
+/** @name Aliases for old function names.
+ * @{
+ */
+#if !defined(PDMPCIDEVICE_NO_DEPRECATED) || defined(DOXYGEN_RUNNING)
+# define PCIDevSetByte               PDMPciDevSetByte
+# define PCIDevGetByte               PDMPciDevGetByte
+# define PCIDevSetWord               PDMPciDevSetWord
+# define PCIDevGetWord               PDMPciDevGetWord
+# define PCIDevSetDWord              PDMPciDevSetDWord
+# define PCIDevGetDWord              PDMPciDevGetDWord
+# define PCIDevSetQWord              PDMPciDevSetQWord
+# define PCIDevGetQWord              PDMPciDevGetQWord
+# define PCIDevSetVendorId           PDMPciDevSetVendorId
+# define PCIDevGetVendorId           PDMPciDevGetVendorId
+# define PCIDevSetDeviceId           PDMPciDevSetDeviceId
+# define PCIDevGetDeviceId           PDMPciDevGetDeviceId
+# define PCIDevSetCommand            PDMPciDevSetCommand
+# define PCIDevGetCommand            PDMPciDevGetCommand
+# define PCIDevIsBusmaster           PDMPciDevIsBusmaster
+# define PCIDevIsIntxDisabled        PDMPciDevIsIntxDisabled
+# define PCIDevGetStatus             PDMPciDevGetStatus
+# define PCIDevSetStatus             PDMPciDevSetStatus
+# define PCIDevSetRevisionId         PDMPciDevSetRevisionId
+# define PCIDevSetClassProg          PDMPciDevSetClassProg
+# define PCIDevSetClassSub           PDMPciDevSetClassSub
+# define PCIDevSetClassBase          PDMPciDevSetClassBase
+# define PCIDevSetHeaderType         PDMPciDevSetHeaderType
+# define PCIDevGetHeaderType         PDMPciDevGetHeaderType
+# define PCIDevSetBIST               PDMPciDevSetBIST
+# define PCIDevGetBIST               PDMPciDevGetBIST
+# define PCIDevSetBaseAddress        PDMPciDevSetBaseAddress
+# define PCIDevGetRegionReg          PDMPciDevGetRegionReg
+# define PCIDevSetSubSystemVendorId  PDMPciDevSetSubSystemVendorId
+# define PCIDevGetSubSystemVendorId  PDMPciDevGetSubSystemVendorId
+# define PCIDevSetSubSystemId        PDMPciDevSetSubSystemId
+# define PCIDevGetSubSystemId        PDMPciDevGetSubSystemId
+# define PCIDevSetCapabilityList     PDMPciDevSetCapabilityList
+# define PCIDevGetCapabilityList     PDMPciDevGetCapabilityList
+# define PCIDevSetInterruptLine      PDMPciDevSetInterruptLine
+# define PCIDevGetInterruptLine      PDMPciDevGetInterruptLine
+# define PCIDevSetInterruptPin       PDMPciDevSetInterruptPin
+# define PCIDevGetInterruptPin       PDMPciDevGetInterruptPin
+#endif
+/** @} */
+
+
+/** @} */
+
+#endif
diff --git a/src/VBox/Devices/Bus/PCIInternal.h b/include/VBox/vmm/pdmpcidevint.h
similarity index 55%
rename from src/VBox/Devices/Bus/PCIInternal.h
rename to include/VBox/vmm/pdmpcidevint.h
index b60bfa1..37067c8 100644
--- a/src/VBox/Devices/Bus/PCIInternal.h
+++ b/include/VBox/vmm/pdmpcidevint.h
@@ -1,6 +1,6 @@
-/* $Id: PCIInternal.h $ */
+/* $Id: pdmpcidevint.h $ */
 /** @file
- * DevPCI - PCI Internal header - Only for hiding bits of PCIDEVICE.
+ * DevPCI - PDM PCI Internal header - Only for hiding bits of PDMPCIDEV.
  */
 
 /*
@@ -15,8 +15,21 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
 
-#ifndef __PCIInternal_h__
-#define __PCIInternal_h__
+#ifndef ___VBox_vmm_pdmpcidevint_h
+#define ___VBox_vmm_pdmpcidevint_h
+
+#include <VBox/vmm/pdmdev.h>
+
+/** @defgroup grp_pdm_pcidev_int    The PDM PCI Device Internals
+ * @ingroup grp_pdm_pcidev
+ *
+ * @remarks The PDM PCI device internals are visible to both PDM and the PCI Bus
+ *          implementation, thus it lives among the the public headers despite
+ *          being rather private and internal.
+ *
+ * @{
+ */
+
 
 /**
  * PCI I/O region.
@@ -71,92 +84,134 @@ typedef PFNPCIBRIDGECONFIGWRITE *PPFNPCIBRIDGECONFIGWRITE;
 struct PCIBus;
 
 enum {
-    /** Set if the specific device function was requested by PDM.
-     * If clear the device and it's functions can be relocated to satisfy the slot request of another device. */
-    PCIDEV_FLAG_REQUESTED_DEVFUNC  = 1<<0,
     /** Flag whether the device is a pci-to-pci bridge.
      * This is set prior to device registration.  */
-    PCIDEV_FLAG_PCI_TO_PCI_BRIDGE  = 1<<1,
+    PCIDEV_FLAG_PCI_TO_PCI_BRIDGE  = RT_BIT_32(1),
     /** Flag whether the device is a PCI Express device.
      * This is set prior to device registration.  */
-    PCIDEV_FLAG_PCI_EXPRESS_DEVICE = 1<<2,
+    PCIDEV_FLAG_PCI_EXPRESS_DEVICE = RT_BIT_32(2),
     /** Flag whether the device is capable of MSI.
      * This one is set by MsiInit().  */
-    PCIDEV_FLAG_MSI_CAPABLE        = 1<<3,
+    PCIDEV_FLAG_MSI_CAPABLE        = RT_BIT_32(3),
     /** Flag whether the device is capable of MSI-X.
      * This one is set by MsixInit().  */
-    PCIDEV_FLAG_MSIX_CAPABLE       = 1<<4,
+    PCIDEV_FLAG_MSIX_CAPABLE       = RT_BIT_32(4),
     /** Flag if device represents real physical device in passthrough mode. */
-    PCIDEV_FLAG_PASSTHROUGH        = 1<<5,
+    PCIDEV_FLAG_PASSTHROUGH        = RT_BIT_32(5),
     /** Flag whether the device is capable of MSI using 64-bit address.  */
-    PCIDEV_FLAG_MSI64_CAPABLE      = 1<<6
+    PCIDEV_FLAG_MSI64_CAPABLE      = RT_BIT_32(6)
 
 };
 
+
 /**
- * PCI Device - Internal data.
+ * PDM PCI Device - Internal data.
+ *
+ * @sa PDMPCIDEV
  */
-typedef struct PCIDEVICEINT
+typedef struct PDMPCIDEVINT
 {
-    /** I/O regions. */
-    PCIIOREGION                     aIORegions[PCI_NUM_REGIONS];
+    /** @name Owned by PDM.
+     * @remarks The bus may use the device instance pointers.
+     * @{
+     */
+    /** Pointer to the PDM device the PCI device belongs to. (R3 ptr)  */
+    PPDMDEVINSR3                    pDevInsR3;
+    /** Pointer to the next PDM device associate with the PDM device. (R3 ptr) */
+    R3PTRTYPE(PPDMPCIDEV)        pNextR3;
+    /** Pointer to the internal PDM PCI bus for the device. (R3 ptr) */
+    R3PTRTYPE(struct PDMPCIBUS *)   pPdmBusR3;
+
+    /** Pointer to the PDM device the PCI device belongs to. (R0 ptr)  */
+    PPDMDEVINSR0                    pDevInsR0;
+    /** Pointer to the next PDM device associate with the PDM device. (R0 ptr) */
+    R0PTRTYPE(PPDMPCIDEV)        pNextR0;
+    /** Pointer to the internal PDM PCI bus for the device. (R0 ptr) */
+    R0PTRTYPE(struct PDMPCIBUS *)   pPdmBusR0;
+
+    /** Pointer to the PDM device the PCI device belongs to. (RC ptr)  */
+    PPDMDEVINSRC                    pDevInsRC;
+    /** Pointer to the next PDM device associate with the PDM device. (RC ptr) */
+    RCPTRTYPE(PPDMPCIDEV)        pNextRC;
+    /** Pointer to the internal PDM PCI bus for the device. (RC ptr) */
+    RCPTRTYPE(struct PDMPCIBUS *)   pPdmBusRC;
+
+    /** The CFGM device configuration index (default, PciDev1..255).
+     * This also works as the internal sub-device ordinal with MMIOEx. */
+    uint8_t                         idxDevCfg;
+    /** Set if the it can be reassigned to a different PCI device number. */
+    bool                            fReassignableDevNo;
+    /** Set if the it can be reassigned to a different PCI function number. */
+    bool                            fReassignableFunNo;
+    /** Alignment padding.   */
+    uint8_t                         bPadding0;
+    /** @} */
+
+    /** @name Owned by the PCI Bus
+     * @remarks PDM will not touch anything here (includes not relocating anything).
+     * @{
+     */
     /** Pointer to the PCI bus of the device. (R3 ptr) */
     R3PTRTYPE(struct PCIBus *)      pBusR3;
-    /** Pointer to the PCI bus of the device. (R0 ptr) */
-    R0PTRTYPE(struct PCIBus *)      pBusR0;
-    /** Pointer to the PCI bus of the device. (RC ptr) */
-    RCPTRTYPE(struct PCIBus *)      pBusRC;
-#if HC_ARCH_BITS == 64
-    RTRCPTR                         Alignment0;
-#endif
-
     /** Page used for MSI-X state.             (R3 ptr) */
-    R3PTRTYPE(void*)                pMsixPageR3;
-    /** Page used for MSI-X state.             (R0 ptr) */
-    R0PTRTYPE(void*)                pMsixPageR0;
-    /** Page used for MSI-X state.             (RC ptr) */
-    RCPTRTYPE(void*)                pMsixPageRC;
-#if HC_ARCH_BITS == 64
-    RTRCPTR                         Alignment1;
-#endif
-
-
+    R3PTRTYPE(void *)               pMsixPageR3;
     /** Read config callback. */
     R3PTRTYPE(PFNPCICONFIGREAD)     pfnConfigRead;
     /** Write config callback. */
     R3PTRTYPE(PFNPCICONFIGWRITE)    pfnConfigWrite;
+    /** Read config callback for PCI bridges to pass requests
+     * to devices on another bus. */
+    R3PTRTYPE(PFNPCIBRIDGECONFIGREAD) pfnBridgeConfigRead;
+    /** Write config callback for PCI bridges to pass requests
+     * to devices on another bus. */
+    R3PTRTYPE(PFNPCIBRIDGECONFIGWRITE) pfnBridgeConfigWrite;
+
+    /** Pointer to the PCI bus of the device. (R0 ptr) */
+    R0PTRTYPE(struct PCIBus *)      pBusR0;
+    /** Page used for MSI-X state.             (R0 ptr) */
+    R0PTRTYPE(void *)               pMsixPageR0;
+
+    /** Pointer to the PCI bus of the device. (RC ptr) */
+    RCPTRTYPE(struct PCIBus *)      pBusRC;
+    /** Page used for MSI-X state.             (RC ptr) */
+    RCPTRTYPE(void *)               pMsixPageRC;
 
     /** Flags of this PCI device, see PCIDEV_FLAG_XXX constants. */
     uint32_t                        fFlags;
     /** Current state of the IRQ pin of the device. */
     int32_t                         uIrqPinState;
 
-    /** Offset of MSI PCI capability in config space, or 0. */
+    /** Offset of MSI PCI capability in config space, or 0.
+     * @todo fix non-standard naming.  */
     uint8_t                         u8MsiCapOffset;
-    /** Size of MSI PCI capability in config space, or 0. */
+    /** Size of MSI PCI capability in config space, or 0.
+     * @todo fix non-standard naming.  */
     uint8_t                         u8MsiCapSize;
-    /** Offset of MSI-X PCI capability in config space, or 0. */
+    /** Offset of MSI-X PCI capability in config space, or 0.
+     * @todo fix non-standard naming.  */
     uint8_t                         u8MsixCapOffset;
-    /** Size of MSI-X PCI capability in config space, or 0. */
+    /** Size of MSI-X PCI capability in config space, or 0.
+     * @todo fix non-standard naming.  */
     uint8_t                         u8MsixCapSize;
+#if HC_ARCH_BITS == 64
+    /** Explicit alignment padding.   */
+    uint8_t                         abPadding1[HC_ARCH_BITS == 32 ? 0 : 4];
+#endif
 
-    uint32_t                        Alignment2;
-
-    /** Pointer to bus specific data.                 (R3 ptr) */
-    R3PTRTYPE(const void*)          pPciBusPtrR3;
+    /** Pointer to bus specific data. (R3 ptr) */
+    R3PTRTYPE(const void *)         pPciBusPtrR3;
 
-    /** Read config callback for PCI bridges to pass requests
-     *  to devices on another bus.
-     */
-    R3PTRTYPE(PFNPCIBRIDGECONFIGREAD) pfnBridgeConfigRead;
-    /** Write config callback for PCI bridges to pass requests
-     *  to devices on another bus.
-     */
-    R3PTRTYPE(PFNPCIBRIDGECONFIGWRITE) pfnBridgeConfigWrite;
+    /** I/O regions. */
+    PCIIOREGION                     aIORegions[VBOX_PCI_NUM_REGIONS];
+    /** @}  */
+} PDMPCIDEVINT;
+AssertCompileMemberAlignment(PDMPCIDEVINT, aIORegions, 8);
+AssertCompileSize(PDMPCIDEVINT, HC_ARCH_BITS == 32 ? 264 : 384);
 
-} PCIDEVICEINT;
+/** Indicate that PDMPCIDEV::Int.s can be declared. */
+#define PDMPCIDEVINT_DECLARED
 
-/** Indicate that PCIDEVICE::Int.s can be declared. */
-#define PCIDEVICEINT_DECLARED
+/** @} */
 
 #endif
+
diff --git a/include/VBox/vmm/pgm.h b/include/VBox/vmm/pgm.h
index 4871166..ff56295 100644
--- a/include/VBox/vmm/pgm.h
+++ b/include/VBox/vmm/pgm.h
@@ -740,13 +740,15 @@ VMMR3DECL(int)      PGMR3QueryGlobalMemoryStats(PUVM pUVM, uint64_t *pcbAllocMem
 VMMR3DECL(int)      PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMPHYSHANDLERTYPE hType,
                                           RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC, const char *pszDesc);
 VMMR3DECL(int)      PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb);
-VMMR3DECL(int)      PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc);
-VMMR3DECL(int)      PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion);
-VMMR3DECL(int)      PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
-VMMR3DECL(int)      PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
-VMMR3DECL(bool)     PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys);
-VMMR3DECL(int)      PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys);
-VMMR3DECL(int)      PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTR0PTR pR0Ptr);
+VMMR3DECL(int)      PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc);
+VMMR3DECL(int)      PGMR3PhysMMIOExPreRegister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRegion, PGMPHYSHANDLERTYPE hType,
+                                               RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC, const char *pszDesc);
+VMMR3DECL(int)      PGMR3PhysMMIOExDeregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion);
+VMMR3DECL(int)      PGMR3PhysMMIOExMap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS GCPhys);
+VMMR3DECL(int)      PGMR3PhysMMIOExUnmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS GCPhys);
+VMMR3DECL(bool)     PGMR3PhysMMIOExIsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys);
+VMMR3_INT_DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys);
+VMMR3_INT_DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTR0PTR pR0Ptr);
 
 /** @name PGMR3PhysRegisterRom flags.
  * @{ */
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
index 51812da..0b91b92 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
@@ -78,6 +78,7 @@ static int vgdrvSolarisQuiesce(dev_info_t *pDip);
 
 static int vgdrvSolarisAddIRQ(dev_info_t *pDip);
 static void vgdrvSolarisRemoveIRQ(dev_info_t *pDip);
+static uint_t vgdrvSolarisHighLevelISR(caddr_t Arg);
 static uint_t vgdrvSolarisISR(caddr_t Arg);
 
 
@@ -177,20 +178,24 @@ static uint16_t             g_uIOPortBase;
 static caddr_t              g_pMMIOBase;
 /** Size of the MMIO region. */
 static off_t                g_cbMMIO;
-/** Pointer to the interrupt handle vector */
-static ddi_intr_handle_t   *g_pIntr;
-/** Number of actually allocated interrupt handles */
-static size_t               g_cIntrAllocated;
+/** Pointer to an array of interrupt handles. */
+static ddi_intr_handle_t   *g_pahIntrs;
+/** Handle to the soft interrupt. */
+static ddi_softint_handle_t g_hSoftIntr;
 /** The pollhead structure */
 static pollhead_t           g_PollHead;
 /** The IRQ Mutex */
 static kmutex_t             g_IrqMtx;
+/** The IRQ high-level Mutex. */
+static kmutex_t             g_HighLevelIrqMtx;
 /** Layered device handle for kernel keep-attached opens */
 static ldi_handle_t         g_LdiHandle = NULL;
 /** Ref counting for IDCOpen calls */
 static uint64_t             g_cLdiOpens = 0;
 /** The Mutex protecting the LDI handle in IDC opens */
 static kmutex_t             g_LdiMtx;
+/** Whether soft-ints are setup. */
+static bool                 g_fSoftIntRegistered = false;
 
 /**
  * Kernel entry points
@@ -352,6 +357,7 @@ static int vgdrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
                                 }
                                 else
                                     LogRel((DEVICE_NAME "::Attach: VGDrvCommonInitDevExt failed.\n"));
+
                                 vgdrvSolarisRemoveIRQ(pDip);
                             }
                             else
@@ -432,12 +438,9 @@ static int vgdrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
  */
 static int vgdrvSolarisQuiesce(dev_info_t *pDip)
 {
-    for (int i = 0; i < g_cIntrAllocated; i++)
-    {
-        int rc = ddi_intr_disable(g_pIntr[i]);
-        if (rc != DDI_SUCCESS)
-            return DDI_FAILURE;
-    }
+    int rc = ddi_intr_disable(g_pahIntrs[0]);
+    if (rc != DDI_SUCCESS)
+        return DDI_FAILURE;
 
     /** @todo What about HGCM/HGSMI touching guest-memory? */
 
@@ -602,6 +605,43 @@ static int vgdrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
 
 
 /**
+ * Converts a VBox status code to a Solaris error code.
+ *
+ * @returns corresponding Solaris errno.
+ * @param   rcVBox        VirtualBox error code to convert.
+ */
+static int vgdrvSolarisConvertToErrno(int rcVBox)
+{
+    /* RTErrConvertToErrno() below will ring-0 debug assert if we don't do such stuff. */
+    if (rcVBox == VERR_PERMISSION_DENIED)
+        rcVBox = VERR_ACCESS_DENIED;
+
+    if (   rcVBox > -1000
+        && rcVBox < 1000)
+        return RTErrConvertToErrno(rcVBox);
+
+    switch (rcVBox)
+    {
+        case VERR_HGCM_SERVICE_NOT_FOUND:      return ESRCH;
+        case VINF_HGCM_CLIENT_REJECTED:        return 0;
+        case VERR_HGCM_INVALID_CMD_ADDRESS:    return EFAULT;
+        case VINF_HGCM_ASYNC_EXECUTE:          return 0;
+        case VERR_HGCM_INTERNAL:               return EPROTO;
+        case VERR_HGCM_INVALID_CLIENT_ID:      return EINVAL;
+        case VINF_HGCM_SAVE_STATE:             return 0;
+        /* No reason to return this to a guest. */
+        /* case VERR_HGCM_SERVICE_EXISTS:      return EEXIST; */
+
+        default:
+        {
+            AssertMsgFailed(("Unhandled error code %Rrc\n", rcVBox));
+            return EINVAL;
+        }
+    }
+}
+
+
+/**
  * Driver ioctl, an alternate entry point for this character driver.
  *
  * @param   Dev             Device number
@@ -723,9 +763,7 @@ static int vgdrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t
          * which are not really failures that require logging.
          */
         Log(("vgdrvSolarisIOCtl: VGDrvCommonIoCtl failed. Cmd=%#x rc=%d\n", Cmd, rc));
-        if (rc == VERR_PERMISSION_DENIED)   /* RTErrConvertToErrno() below will ring-0 debug assert if we don't do this. */
-            rc = VERR_ACCESS_DENIED;
-        rc = RTErrConvertToErrno(rc);
+        rc = vgdrvSolarisConvertToErrno(rc);
     }
     *pVal = rc;
     if (pvBuf)
@@ -775,88 +813,119 @@ static int vgdrvSolarisAddIRQ(dev_info_t *pDip)
 {
     LogFlow(("vgdrvSolarisAddIRQ: pDip=%p\n", pDip));
 
-    int IntrType = 0;
-    int rc = ddi_intr_get_supported_types(pDip, &IntrType);
+    /* Get the types of interrupt supported for this hardware. */
+    int fIntrType = 0;
+    int rc = ddi_intr_get_supported_types(pDip, &fIntrType);
     if (rc == DDI_SUCCESS)
     {
-        /* We won't need to bother about MSIs. */
-        if (IntrType & DDI_INTR_TYPE_FIXED)
+        /* We only support fixed interrupts at this point, not MSIs. */
+        if (fIntrType & DDI_INTR_TYPE_FIXED)
         {
-            int IntrCount = 0;
-            rc = ddi_intr_get_nintrs(pDip, IntrType, &IntrCount);
+            /* Verify the number of interrupts supported by this device. There can only be one fixed interrupt. */
+            int cIntrCount = 0;
+            rc = ddi_intr_get_nintrs(pDip, fIntrType, &cIntrCount);
             if (   rc == DDI_SUCCESS
-                && IntrCount > 0)
+                && cIntrCount == 1)
             {
-                int IntrAvail = 0;
-                rc = ddi_intr_get_navail(pDip, IntrType, &IntrAvail);
-                if (   rc == DDI_SUCCESS
-                    && IntrAvail > 0)
+                /* Allocated kernel memory for the interrupt handle. The allocation size is stored internally. */
+                g_pahIntrs = RTMemAllocZ(cIntrCount * sizeof(ddi_intr_handle_t));
+                if (g_pahIntrs)
                 {
-                    /* Allocated kernel memory for the interrupt handles. The allocation size is stored internally. */
-                    g_pIntr = RTMemAlloc(IntrCount * sizeof(ddi_intr_handle_t));
-                    if (g_pIntr)
+                    /* Allocate the interrupt for this device and verify the allocation. */
+                    int cIntrAllocated;
+                    rc = ddi_intr_alloc(pDip, g_pahIntrs, fIntrType, 0 /* interrupt number */, cIntrCount, &cIntrAllocated,
+                                        DDI_INTR_ALLOC_NORMAL);
+                    if (   rc == DDI_SUCCESS
+                        && cIntrAllocated == 1)
                     {
-                        int IntrAllocated;
-                        rc = ddi_intr_alloc(pDip, g_pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL);
-                        if (   rc == DDI_SUCCESS
-                            && IntrAllocated > 0)
+                        /* Get the interrupt priority assigned by the system. */
+                        uint_t uIntrPriority;
+                        rc = ddi_intr_get_pri(g_pahIntrs[0], &uIntrPriority);
+                        if (rc == DDI_SUCCESS)
                         {
-                            g_cIntrAllocated = IntrAllocated;
-                            uint_t uIntrPriority;
-                            rc = ddi_intr_get_pri(g_pIntr[0], &uIntrPriority);
-                            if (rc == DDI_SUCCESS)
+                            /* Check if the interrupt priority is scheduler level or above, if so we need to use a high-level
+                               and low-level interrupt handlers with corresponding mutexes. */
+                            cmn_err(CE_NOTE,  "vboxguest: uIntrPriority=%d hilevel_pri=%d\n", uIntrPriority, ddi_intr_get_hilevel_pri());
+                            if (uIntrPriority >= ddi_intr_get_hilevel_pri())
                             {
-                                /* Initialize the mutex. */
-                                mutex_init(&g_IrqMtx, NULL /* pszDesc */, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority));
+                                /* Initialize the high-level mutex. */
+                                mutex_init(&g_HighLevelIrqMtx, NULL /* pszDesc */, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority));
 
-                                /* Assign interrupt handler functions and enable interrupts. */
-                                for (int i = 0; i < IntrAllocated; i++)
+                                /* Assign interrupt handler function to the interrupt handle. */
+                                rc = ddi_intr_add_handler(g_pahIntrs[0], (ddi_intr_handler_t *)&vgdrvSolarisHighLevelISR,
+                                                          NULL /* pvArg1 */, NULL /* pvArg2 */);
+
+                                if (rc == DDI_SUCCESS)
                                 {
-                                    rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)vgdrvSolarisISR,
-                                                              NULL /* pvArg1 */, NULL /* pvArg2 */);
+                                    /* Add the low-level interrupt handler. */
+                                    rc = ddi_intr_add_softint(pDip, &g_hSoftIntr, DDI_INTR_SOFTPRI_MAX,
+                                                              (ddi_intr_handler_t *)&vgdrvSolarisISR, NULL /* pvArg1 */);
                                     if (rc == DDI_SUCCESS)
-                                        rc = ddi_intr_enable(g_pIntr[i]);
-                                    if (rc != DDI_SUCCESS)
                                     {
-                                        /* Changing local IntrAllocated to hold so-far allocated handles for freeing. */
-                                        IntrAllocated = i;
-                                        break;
+                                        /* Initialize the low-level mutex at the corresponding level. */
+                                        mutex_init(&g_IrqMtx, NULL /* pszDesc */,  MUTEX_DRIVER,
+                                                   DDI_INTR_PRI(DDI_INTR_SOFTPRI_MAX));
+
+                                        g_fSoftIntRegistered = true;
+                                        /* Enable the high-level interrupt. */
+                                        rc = ddi_intr_enable(g_pahIntrs[0]);
+                                        if (rc == DDI_SUCCESS)
+                                            return rc;
+
+                                        LogRel((DEVICE_NAME "::AddIRQ: failed to enable interrupt. rc=%d\n", rc));
+                                        mutex_destroy(&g_IrqMtx);
                                     }
+                                    else
+                                        LogRel((DEVICE_NAME "::AddIRQ: failed to add soft interrupt handler. rc=%d\n", rc));
+
+                                    ddi_intr_remove_handler(g_pahIntrs[0]);
                                 }
-                                if (rc == DDI_SUCCESS)
-                                    return rc;
+                                else
+                                    LogRel((DEVICE_NAME "::AddIRQ: failed to add high-level interrupt handler. rc=%d\n", rc));
 
-                                /* Remove any assigned handlers */
-                                LogRel((DEVICE_NAME ":failed to assign IRQs allocated=%d\n", IntrAllocated));
-                                for (int x = 0; x < IntrAllocated; x++)
-                                    ddi_intr_remove_handler(g_pIntr[x]);
+                                mutex_destroy(&g_HighLevelIrqMtx);
                             }
                             else
-                                LogRel((DEVICE_NAME "::AddIRQ: failed to get priority of interrupt. rc=%d\n", rc));
+                            {
+                                /* Interrupt handler runs at reschedulable level, initialize the mutex at the given priority. */
+                                mutex_init(&g_IrqMtx, NULL /* pszDesc */, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority));
+
+                                /* Assign interrupt handler function to the interrupt handle. */
+                                rc = ddi_intr_add_handler(g_pahIntrs[0], (ddi_intr_handler_t *)vgdrvSolarisISR,
+                                                          NULL /* pvArg1 */, NULL /* pvArg2 */);
+                                if (rc == DDI_SUCCESS)
+                                {
+                                    /* Enable the interrupt. */
+                                    rc = ddi_intr_enable(g_pahIntrs[0]);
+                                    if (rc == DDI_SUCCESS)
+                                        return rc;
 
-                            /* Remove allocated IRQs, too bad we can free only one handle at a time. */
-                            for (int k = 0; k < g_cIntrAllocated; k++)
-                                ddi_intr_free(g_pIntr[k]);
-                            g_cIntrAllocated = 0;
+                                    LogRel((DEVICE_NAME "::AddIRQ: failed to enable interrupt. rc=%d\n", rc));
+                                    mutex_destroy(&g_IrqMtx);
+                                }
+                            }
                         }
                         else
-                            LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
-                        RTMemFree(g_pIntr);
+                            LogRel((DEVICE_NAME "::AddIRQ: failed to get priority of interrupt. rc=%d\n", rc));
+
+                        Assert(cIntrAllocated == 1);
+                        ddi_intr_free(g_pahIntrs[0]);
                     }
                     else
-                        LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
+                        LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", cIntrCount));
+                    RTMemFree(g_pahIntrs);
                 }
                 else
-                    LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient available IRQs. rc=%d IntrAvail=%d\n", rc, IntrAvail));
+                    LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", cIntrCount));
             }
             else
-                LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient number of IRQs. rc=%d IntrCount=%d\n", rc, IntrCount));
+                LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient number of IRQs. rc=%d cIntrCount=%d\n", rc, cIntrCount));
         }
         else
-            LogRel((DEVICE_NAME "::AddIRQ: invalid irq type. IntrType=%#x\n", IntrType));
+            LogRel((DEVICE_NAME "::AddIRQ: fixed-type interrupts not supported. IntrType=%#x\n", fIntrType));
     }
     else
-        LogRel((DEVICE_NAME "::AddIRQ: failed to get supported interrupt types\n"));
+        LogRel((DEVICE_NAME "::AddIRQ: failed to get supported interrupt types. rc=%d\n", rc));
     return rc;
 }
 
@@ -870,19 +939,45 @@ static void vgdrvSolarisRemoveIRQ(dev_info_t *pDip)
 {
     LogFlow(("vgdrvSolarisRemoveIRQ:\n"));
 
-    for (int i = 0; i < g_cIntrAllocated; i++)
+    int rc = ddi_intr_disable(g_pahIntrs[0]);
+    if (rc == DDI_SUCCESS)
     {
-        int rc = ddi_intr_disable(g_pIntr[i]);
+        rc = ddi_intr_remove_handler(g_pahIntrs[0]);
         if (rc == DDI_SUCCESS)
-        {
-            rc = ddi_intr_remove_handler(g_pIntr[i]);
-            if (rc == DDI_SUCCESS)
-                ddi_intr_free(g_pIntr[i]);
-        }
+            ddi_intr_free(g_pahIntrs[0]);
+    }
+
+    if (g_fSoftIntRegistered)
+    {
+        ddi_intr_remove_softint(g_hSoftIntr);
+        mutex_destroy(&g_HighLevelIrqMtx);
+        g_fSoftIntRegistered = false;
     }
-    g_cIntrAllocated = 0;
-    RTMemFree(g_pIntr);
+
     mutex_destroy(&g_IrqMtx);
+    RTMemFree(g_pahIntrs);
+}
+
+
+/**
+ * High-level Interrupt Service Routine for VMMDev.
+ *
+ * This routine simply dispatches a soft-interrupt at an acceptable IPL as
+ * VGDrvCommonISR() cannot be called at a high IPL (scheduler level or higher)
+ * due to pollwakeup() in VGDrvNativeISRMousePollEvent().
+ *
+ * @param   Arg     Private data (unused, will be NULL).
+ * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
+ */
+static uint_t vgdrvSolarisHighLevelISR(caddr_t Arg)
+{
+    bool const fOurIrq = VGDrvCommonIsOurIRQ(&g_DevExt);
+    if (fOurIrq)
+    {
+        ddi_intr_trigger_softint(g_hSoftIntr, NULL /* Arg */);
+        return DDI_INTR_CLAIMED;
+    }
+    return DDI_INTR_UNCLAIMED;
 }
 
 
@@ -896,6 +991,8 @@ static uint_t vgdrvSolarisISR(caddr_t Arg)
 {
     LogFlow(("vgdrvSolarisISR:\n"));
 
+    /* The mutex is required to protect against parallel executions (if possible?) and also the
+       mouse notify registeration race between VGDrvNativeSetMouseNotifyCallback() and VGDrvCommonISR(). */
     mutex_enter(&g_IrqMtx);
     bool fOurIRQ = VGDrvCommonISR(&g_DevExt);
     mutex_exit(&g_IrqMtx);
@@ -904,6 +1001,13 @@ static uint_t vgdrvSolarisISR(caddr_t Arg)
 }
 
 
+/**
+ * Poll notifier for mouse poll events.
+ *
+ * @param   pDevExt   Pointer to the device extension.
+ *
+ * @remarks This must be called without holding any spinlocks.
+ */
 void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
 {
     LogFlow(("VGDrvNativeISRMousePollEvent:\n"));
@@ -915,6 +1019,23 @@ void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
 }
 
 
+/**
+ * Sets the mouse notification callback.
+ *
+ * @returns VBox status code.
+ * @param   pDevExt   Pointer to the device extension.
+ * @param   pNotify   Pointer to the mouse notify struct.
+ */
+int VGDrvNativeSetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGuestMouseSetNotifyCallback *pNotify)
+{
+    /* Take the mutex here so as to not race with VGDrvCommonISR() which invokes the mouse notify callback. */
+    mutex_enter(&g_IrqMtx);
+    pDevExt->MouseNotifyCallback = *pNotify;
+    mutex_exit(&g_IrqMtx);
+    return VINF_SUCCESS;
+}
+
+
 /* Common code that depend on g_DevExt. */
 #include "VBoxGuestIDC-unix.c.h"
 
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
index 02527b3..6103210 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
@@ -107,8 +107,7 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
     LogFunc(("Driver built: %s %s\n", __DATE__, __TIME__));
 
     /*
-     * Check if the the NT version is supported and initializing
-     * g_enmVGDrvNtVer in the process.
+     * Check if the NT version is supported and initialize g_enmVGDrvNtVer.
      */
     ULONG ulMajorVer;
     ULONG ulMinorVer;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
index 5ecfb01..3166730 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
@@ -1559,9 +1559,13 @@ int vgdrvIoCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGuestMouseSe
 {
     LogFlow(("VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK: pfnNotify=%p pvUser=%p\n", pNotify->pfnNotify, pNotify->pvUser));
 
+#ifdef VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+    VGDrvNativeSetMouseNotifyCallback(pDevExt, pNotify);
+#else
     RTSpinlockAcquire(pDevExt->EventSpinlock);
     pDevExt->MouseNotifyCallback = *pNotify;
     RTSpinlockRelease(pDevExt->EventSpinlock);
+#endif
     return VINF_SUCCESS;
 }
 #endif
@@ -3639,6 +3643,23 @@ static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents)
 
 
 /**
+ * Simply checks whether the IRQ is ours or not, does not do any interrupt
+ * procesing.
+ *
+ * @returns true if it was our interrupt, false if it wasn't.
+ * @param   pDevExt     The VBoxGuest device extension.
+ */
+bool VGDrvCommonIsOurIRQ(PVBOXGUESTDEVEXT pDevExt)
+{
+    RTSpinlockAcquire(pDevExt->EventSpinlock);
+    bool const fOurIrq = pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents;
+    RTSpinlockRelease(pDevExt->EventSpinlock);
+
+    return fOurIrq;
+}
+
+
+/**
  * Common interrupt service routine.
  *
  * This deals with events and with waking up thread waiting for those events.
@@ -3688,7 +3709,7 @@ bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt)
             {
                 fMousePositionChanged = true;
                 fEvents &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
-#ifndef RT_OS_WINDOWS
+#if !defined(RT_OS_WINDOWS) && !defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
                 if (pDevExt->MouseNotifyCallback.pfnNotify)
                     pDevExt->MouseNotifyCallback.pfnNotify(pDevExt->MouseNotifyCallback.pvUser);
 #endif
@@ -3734,6 +3755,16 @@ bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt)
 
     RTSpinlockRelease(pDevExt->EventSpinlock);
 
+    /*
+     * Execute the mouse notification callback here if it cannot be executed while
+     * holding the interrupt safe spinlock, see @bugref{8639}.
+     */
+#if defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
+    if (   fMousePositionChanged
+        && pDevExt->MouseNotifyCallback.pfnNotify)
+        pDevExt->MouseNotifyCallback.pfnNotify(pDevExt->MouseNotifyCallback.pvUser);
+#endif
+
 #if defined(VBOXGUEST_USE_DEFERRED_WAKE_UP) && !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS)
     /*
      * Do wake-ups.
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
index 9807872..c5b652b 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
@@ -42,6 +42,13 @@
 # define VBOXGUEST_USE_DEFERRED_WAKE_UP
 #endif
 
+/** @def VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+ * The mouse notification callback can cause preemption and must not be invoked
+ * while holding a high-level spinlock.
+ */
+#if defined(RT_OS_SOLARIS) || defined(DOXYGEN_RUNNING)
+# define VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+#endif
 
 /** Pointer to the VBoxGuest per session data. */
 typedef struct VBOXGUESTSESSION *PVBOXGUESTSESSION;
@@ -315,6 +322,7 @@ RT_C_DECLS_BEGIN
 
 int  VGDrvCommonInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase, void *pvMMIOBase, uint32_t cbMMIO,
                            VBOXOSTYPE enmOSType, uint32_t fEvents);
+bool VGDrvCommonIsOurIRQ(PVBOXGUESTDEVEXT pDevExt);
 bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt);
 void VGDrvCommonDeleteDevExt(PVBOXGUESTDEVEXT pDevExt);
 int  VGDrvCommonReinitDevExtAfterHibernation(PVBOXGUESTDEVEXT pDevExt, VBOXOSTYPE enmOSType);
@@ -345,6 +353,10 @@ void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt);
 int VGDrvNtIOCtl_DpcLatencyChecker(void);
 #endif
 
+#ifdef VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+int VGDrvNativeSetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGuestMouseSetNotifyCallback *pNotify);
+#endif
+
 RT_C_DECLS_END
 
 #endif
diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibAdditions.cpp b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibAdditions.cpp
index 61f46e5..ef429ea 100644
--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibAdditions.cpp
+++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibAdditions.cpp
@@ -103,7 +103,7 @@ static int vbglR3WinCloseRegKey(HKEY hKey, int rc)
  *
  * @return  IPRT status code.
  * @param   hKey                Handle of registry key to use.
- * @param   pwszValueName       The the name of the value to query.
+ * @param   pwszValueName       The name of the value to query.
  * @param   cbHint              Size hint.
  * @param   ppszValue           Where to return value string on success. Free
  *                              with RTStrFree.
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
index fbe6f7d..49d9ba5 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo-win.cpp
@@ -33,6 +33,7 @@
 #include <iprt/localipc.h>
 #include <iprt/mem.h>
 #include <iprt/once.h>
+#include <iprt/process.h>
 #include <iprt/string.h>
 #include <iprt/semaphore.h>
 #include <iprt/system.h>
@@ -953,17 +954,16 @@ static int vgsvcVMInfoWinWriteLastInput(PVBOXSERVICEVEPROPCACHE pCache, const ch
     AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
     /* pszDomain is optional. */
 
-    int rc = VINF_SUCCESS;
-
-    char szPipeName[255];
-/** @todo r=bird:  Pointless if.  */
-    if (RTStrPrintf(szPipeName, sizeof(szPipeName), "%s%s", VBOXTRAY_IPC_PIPE_PREFIX, pszUser))
+    char szPipeName[512 + sizeof(VBOXTRAY_IPC_PIPE_PREFIX)];
+    memcpy(szPipeName, VBOXTRAY_IPC_PIPE_PREFIX, sizeof(VBOXTRAY_IPC_PIPE_PREFIX));
+    int rc = RTStrCat(szPipeName, sizeof(szPipeName), pszUser);
+    if (RT_SUCCESS(rc))
     {
         bool fReportToHost = false;
         VBoxGuestUserState userState = VBoxGuestUserState_Unknown;
 
         RTLOCALIPCSESSION hSession;
-        rc = RTLocalIpcSessionConnect(&hSession, szPipeName, 0 /* Flags */);
+        rc = RTLocalIpcSessionConnect(&hSession, szPipeName, RTLOCALIPC_FLAGS_NATIVE_NAME);
         if (RT_SUCCESS(rc))
         {
             VBOXTRAYIPCHEADER ipcHdr =
diff --git a/src/VBox/Additions/common/crOpenGL/dri_util.c b/src/VBox/Additions/common/crOpenGL/dri_util.c
index d89968d..23884fd 100644
--- a/src/VBox/Additions/common/crOpenGL/dri_util.c
+++ b/src/VBox/Additions/common/crOpenGL/dri_util.c
@@ -820,7 +820,7 @@ setupLoaderExtensions(__DRIscreen *psp,
  * \param drm_version Version of the kernel DRM.
  * \param frame_buffer Data describing the location and layout of the
  *                     framebuffer.
- * \param pSAREA       Pointer the the SAREA.
+ * \param pSAREA       Pointer to the SAREA.
  * \param fd           Device handle for the DRM.
  * \param extensions   ??
  * \param driver_modes  Returns modes supported by the driver
diff --git a/src/VBox/Additions/freebsd/Makefile.kmk b/src/VBox/Additions/freebsd/Makefile.kmk
index 4585fbf..4dee00b 100644
--- a/src/VBox/Additions/freebsd/Makefile.kmk
+++ b/src/VBox/Additions/freebsd/Makefile.kmk
@@ -86,7 +86,7 @@ VBOX_FBSD_ADD_DBG_SYM_FILES := $(addsuffix .dbgsym,$(VBOX_FBSD_ADD_STRIP_BIN))
 VBOX_FBSD_ADD_INS_FILES := $(addprefix $(VBOX_FBSD_ADD_INS_OUT_DIR)/,$(VBOX_FBSD_ADD_STRIP_BIN) $(VBOX_FBSD_ADD_STRIP_OBJ) $(VBOX_FBSD_ADD_DBG_SYM_FILES))
 VBOX_FBSD_ADD_INS_MODULES := $(addprefix $(VBOX_FBSD_ADD_INS_OUT_DIR)/module/,$(VBOX_FBSD_ADD_MODULES))
 
-# Cleanup of the the installer directory files
+# Cleanup of the installer directory files
 OTHER_CLEAN += $(VBOX_FBSD_ADD_INS_FILES)) $(VBOX_FBSD_ADD_INS_MODULES)
 
 # pattern rule for copying the debug info from the VBOX_FBSD_ADD_STRIP_BIN files to the installation directory
diff --git a/src/VBox/Additions/linux/Makefile.kmk b/src/VBox/Additions/linux/Makefile.kmk
index 571f3c9..ed87950 100644
--- a/src/VBox/Additions/linux/Makefile.kmk
+++ b/src/VBox/Additions/linux/Makefile.kmk
@@ -205,7 +205,7 @@ VBOX_LNX_ADD_INST_FILES += \
 	$(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),vbox-greeter)
 endif
 
-# Cleanup of the the installer directory files
+# Cleanup of the installer directory files
 OTHER_CLEAN += $(VBOX_LNX_ADD_INST_FILES) $(VBOX_LNX_ADD_DBG_FILES)
 
 # pattern rules for copying the debug info from the VBOX_LNX_ADD_STRIP_* files to the installation directory
diff --git a/src/VBox/Additions/linux/drm/vbox_ttm.c b/src/VBox/Additions/linux/drm/vbox_ttm.c
index 74f9f5a..0e23acd 100644
--- a/src/VBox/Additions/linux/drm/vbox_ttm.c
+++ b/src/VBox/Additions/linux/drm/vbox_ttm.c
@@ -223,8 +223,10 @@ static int vbox_bo_move(struct ttm_buffer_object *bo,
     int r;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
     r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
-#else
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
     r = ttm_bo_move_memcpy(bo, evict, interruptible, no_wait_gpu, new_mem);
+#else
+    r = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem);
 #endif
     return r;
 }
diff --git a/src/VBox/Additions/linux/installer/vboxadd-x11.sh b/src/VBox/Additions/linux/installer/vboxadd-x11.sh
index 604f63c..0364c74 100755
--- a/src/VBox/Additions/linux/installer/vboxadd-x11.sh
+++ b/src/VBox/Additions/linux/installer/vboxadd-x11.sh
@@ -1,6 +1,6 @@
 #! /bin/sh
 #
-# Linux Additions X11 setup init script ($Revision: 110817 $)
+# Linux Additions X11 setup init script ($Revision: 111712 $)
 #
 
 #
@@ -454,7 +454,7 @@ $generated
 
 EOF
         cat << EOF
-You may need to restart the the Window System (or just restart the guest system)
+You may need to restart the Window System (or just restart the guest system)
 to enable the Guest Additions.
 
 EOF
diff --git a/src/VBox/Additions/linux/installer/vboxadd.sh b/src/VBox/Additions/linux/installer/vboxadd.sh
index f423d46..9bbd0b4 100755
--- a/src/VBox/Additions/linux/installer/vboxadd.sh
+++ b/src/VBox/Additions/linux/installer/vboxadd.sh
@@ -1,6 +1,6 @@
 #! /bin/sh
 #
-# Linux Additions kernel module init script ($Revision: 111368 $)
+# Linux Additions kernel module init script ($Revision: 111985 $)
 #
 
 #
@@ -329,8 +329,8 @@ setup_modules()
     fi
     succ_msg
     echo "override vboxguest * misc" > /etc/depmod.d/vboxvideo-upstream.conf
-    echo "override vboxsf * misc" > /etc/depmod.d/vboxvideo-upstream.conf
-    echo "override vboxvideo * misc" > /etc/depmod.d/vboxvideo-upstream.conf
+    echo "override vboxsf * misc" >> /etc/depmod.d/vboxvideo-upstream.conf
+    echo "override vboxvideo * misc" >> /etc/depmod.d/vboxvideo-upstream.conf
     depmod
     return 0
 }
diff --git a/src/VBox/Additions/linux/sharedfolders/dirops.c b/src/VBox/Additions/linux/sharedfolders/dirops.c
index 571f807..0267b0b 100644
--- a/src/VBox/Additions/linux/sharedfolders/dirops.c
+++ b/src/VBox/Additions/linux/sharedfolders/dirops.c
@@ -745,16 +745,29 @@ static int sf_rmdir(struct inode *parent, struct dentry *dentry)
  * @param old_dentry    old directory cache entry
  * @param new_parent    inode of the new parent directory
  * @param new_dentry    new directory cache entry
+ * @param flags         flags
  * @returns 0 on success, Linux error code otherwise
  */
 static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
-                     struct inode *new_parent, struct dentry *new_dentry)
+                     struct inode *new_parent, struct dentry *new_dentry
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+                     , unsigned flags
+#endif
+                     )
 {
     int err = 0, rc = VINF_SUCCESS;
     struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb);
 
     TRACE();
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+    if (flags)
+    {
+        LogFunc(("rename with flags=%x\n", flags));
+        return -EINVAL;
+    }
+#endif
+
     if (sf_g != GET_GLOB_INFO(new_parent->i_sb))
     {
         LogFunc(("rename with different roots\n"));
diff --git a/src/VBox/Devices/Audio/AudioMixer.cpp b/src/VBox/Devices/Audio/AudioMixer.cpp
index e0473ca..d904fc1 100644
--- a/src/VBox/Devices/Audio/AudioMixer.cpp
+++ b/src/VBox/Devices/Audio/AudioMixer.cpp
@@ -513,7 +513,7 @@ int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
  * @param   pConn               Audio connector interface to use.
  * @param   pCfg                Audio stream configuration to use.
  * @param   fFlags              Stream creation flags. Currently unused, set to 0.
- * @param   ppStream            Pointer which receives the the newly created audio stream.
+ * @param   ppStream            Pointer which receives the newly created audio stream.
  */
 int AudioMixerSinkCreateStream(PAUDMIXSINK pSink,
                                PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream)
diff --git a/src/VBox/Devices/Audio/DevIchHda.cpp b/src/VBox/Devices/Audio/DevHDA.cpp
similarity index 99%
copy from src/VBox/Devices/Audio/DevIchHda.cpp
copy to src/VBox/Devices/Audio/DevHDA.cpp
index cf8d68b..2f154c6 100644
--- a/src/VBox/Devices/Audio/DevIchHda.cpp
+++ b/src/VBox/Devices/Audio/DevHDA.cpp
@@ -1,6 +1,6 @@
-/* $Id: DevIchHda.cpp $ */
+/* $Id: DevHDA.cpp $ */
 /** @file
- * DevIchHda - VBox ICH Intel HD Audio Controller.
+ * DevHDA - VBox HD Audio Controller.
  *
  * Implemented against the specifications found in "High Definition Audio
  * Specification", Revision 1.0a June 17, 2010, and  "Intel I/O Controller
@@ -45,8 +45,8 @@
 
 #include "AudioMixBuffer.h"
 #include "AudioMixer.h"
-#include "DevIchHdaCodec.h"
-#include "DevIchHdaCommon.h"
+#include "HDACodec.h"
+#include "DevHDACommon.h"
 #include "DrvAudio.h"
 
 
@@ -772,7 +772,7 @@ typedef struct HDADRIVER
 typedef struct HDASTATE
 {
     /** The PCI device structure. */
-    PCIDevice                          PciDev;
+    PDMPCIDEV                          PciDev;
     /** R3 Pointer to the device instance. */
     PPDMDEVINSR3                       pDevInsR3;
     /** R0 Pointer to the device instance. */
@@ -4766,11 +4766,10 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int)
-hdaPciIoRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int)  hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                            RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, enmType);
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
     PHDASTATE   pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev);
 
     /*
@@ -6258,7 +6257,7 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
     {
         /* Start the emulation timer. */
         rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, hdaTimer, pThis,
-                                    TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchHda", &pThis->pTimer);
+                                    TMTIMER_FLAGS_NO_CRIT_SECT, "DevHDA", &pThis->pTimer);
         AssertRCReturn(rc, rc);
 
         if (RT_SUCCESS(rc))
@@ -6323,7 +6322,7 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
 /**
  * The device registration structure.
  */
-const PDMDEVREG g_DeviceICH6_HDA =
+const PDMDEVREG g_DeviceHDA =
 {
     /* u32Version */
     PDM_DEVREG_VERSION,
diff --git a/src/VBox/Devices/Audio/DevIchHdaCommon.h b/src/VBox/Devices/Audio/DevHDACommon.h
similarity index 99%
rename from src/VBox/Devices/Audio/DevIchHdaCommon.h
rename to src/VBox/Devices/Audio/DevHDACommon.h
index 3c1c040..7b2dca8 100644
--- a/src/VBox/Devices/Audio/DevIchHdaCommon.h
+++ b/src/VBox/Devices/Audio/DevHDACommon.h
@@ -1,4 +1,4 @@
-/* $Id: DevIchHdaCommon.h $ */
+/* $Id: DevHDACommon.h $ */
 /** @file
  * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
  */
diff --git a/src/VBox/Devices/Audio/DevIchAc97.cpp b/src/VBox/Devices/Audio/DevIchAc97.cpp
index cedaa62..ed8de3d 100644
--- a/src/VBox/Devices/Audio/DevIchAc97.cpp
+++ b/src/VBox/Devices/Audio/DevIchAc97.cpp
@@ -354,7 +354,7 @@ typedef struct AC97DRIVER
 typedef struct AC97STATE
 {
     /** The PCI device state. */
-    PCIDevice               PciDev;
+    PDMPCIDEV               PciDev;
     /** R3 Pointer to the device instance. */
     PPDMDEVINSR3            pDevInsR3;
     /** Global Control (Bus Master Control Register). */
@@ -2277,18 +2277,17 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int)
-ichac97IOPortMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ichac97IOPortMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                          RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(cb, enmType);
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
     PAC97STATE  pThis   = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
     RTIOPORT    Port    = (RTIOPORT)GCPhysAddress;
 
     Assert(enmType == PCI_ADDRESS_SPACE_IO);
     Assert(cb >= 0x20);
 
-    if (iRegion < 0 || iRegion > 1) /* We support 2 regions max. at the moment. */
+    if (iRegion > 1) /* We support 2 regions max. at the moment. */
         return VERR_INVALID_PARAMETER;
 
     int rc;
@@ -2792,21 +2791,21 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
     pThis->IBase.pfnQueryInterface  = ichac97QueryInterface;
 
     /* PCI Device (the assertions will be removed later) */
-    PCIDevSetVendorId         (&pThis->PciDev, 0x8086); /* 00 ro - intel. */               Assert(pThis->PciDev.config[0x00] == 0x86); Assert(pThis->PciDev.config[0x01] == 0x80);
-    PCIDevSetDeviceId         (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */  Assert(pThis->PciDev.config[0x02] == 0x15); Assert(pThis->PciDev.config[0x03] == 0x24);
-    PCIDevSetCommand          (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */           Assert(pThis->PciDev.config[0x04] == 0x00); Assert(pThis->PciDev.config[0x05] == 0x00);
-    PCIDevSetStatus           (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM |  VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */      Assert(pThis->PciDev.config[0x06] == 0x80); Assert(pThis->PciDev.config[0x07] == 0x02);
-    PCIDevSetRevisionId       (&pThis->PciDev, 0x01);   /* 08 ro - rid. */                 Assert(pThis->PciDev.config[0x08] == 0x01);
-    PCIDevSetClassProg        (&pThis->PciDev, 0x00);   /* 09 ro - pi. */                  Assert(pThis->PciDev.config[0x09] == 0x00);
-    PCIDevSetClassSub         (&pThis->PciDev, 0x01);   /* 0a ro - scc; 01 == Audio. */    Assert(pThis->PciDev.config[0x0a] == 0x01);
-    PCIDevSetClassBase        (&pThis->PciDev, 0x04);   /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.config[0x0b] == 0x04);
-    PCIDevSetHeaderType       (&pThis->PciDev, 0x00);   /* 0e ro - headtyp. */             Assert(pThis->PciDev.config[0x0e] == 0x00);
+    PCIDevSetVendorId         (&pThis->PciDev, 0x8086); /* 00 ro - intel. */               Assert(pThis->PciDev.abConfig[0x00] == 0x86); Assert(pThis->PciDev.abConfig[0x01] == 0x80);
+    PCIDevSetDeviceId         (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */  Assert(pThis->PciDev.abConfig[0x02] == 0x15); Assert(pThis->PciDev.abConfig[0x03] == 0x24);
+    PCIDevSetCommand          (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */           Assert(pThis->PciDev.abConfig[0x04] == 0x00); Assert(pThis->PciDev.abConfig[0x05] == 0x00);
+    PCIDevSetStatus           (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM |  VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */      Assert(pThis->PciDev.abConfig[0x06] == 0x80); Assert(pThis->PciDev.abConfig[0x07] == 0x02);
+    PCIDevSetRevisionId       (&pThis->PciDev, 0x01);   /* 08 ro - rid. */                 Assert(pThis->PciDev.abConfig[0x08] == 0x01);
+    PCIDevSetClassProg        (&pThis->PciDev, 0x00);   /* 09 ro - pi. */                  Assert(pThis->PciDev.abConfig[0x09] == 0x00);
+    PCIDevSetClassSub         (&pThis->PciDev, 0x01);   /* 0a ro - scc; 01 == Audio. */    Assert(pThis->PciDev.abConfig[0x0a] == 0x01);
+    PCIDevSetClassBase        (&pThis->PciDev, 0x04);   /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.abConfig[0x0b] == 0x04);
+    PCIDevSetHeaderType       (&pThis->PciDev, 0x00);   /* 0e ro - headtyp. */             Assert(pThis->PciDev.abConfig[0x0e] == 0x00);
     PCIDevSetBaseAddress      (&pThis->PciDev, 0,       /* 10 rw - nambar - native audio mixer base. */
-                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.config[0x10] == 0x01); Assert(pThis->PciDev.config[0x11] == 0x00); Assert(pThis->PciDev.config[0x12] == 0x00); Assert(pThis->PciDev.config[0x13] == 0x00);
+                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x10] == 0x01); Assert(pThis->PciDev.abConfig[0x11] == 0x00); Assert(pThis->PciDev.abConfig[0x12] == 0x00); Assert(pThis->PciDev.abConfig[0x13] == 0x00);
     PCIDevSetBaseAddress      (&pThis->PciDev, 1,       /* 14 rw - nabmbar - native audio bus mastering. */
-                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.config[0x14] == 0x01); Assert(pThis->PciDev.config[0x15] == 0x00); Assert(pThis->PciDev.config[0x16] == 0x00); Assert(pThis->PciDev.config[0x17] == 0x00);
-    PCIDevSetInterruptLine    (&pThis->PciDev, 0x00);   /* 3c rw. */                       Assert(pThis->PciDev.config[0x3c] == 0x00);
-    PCIDevSetInterruptPin     (&pThis->PciDev, 0x01);   /* 3d ro - INTA#. */               Assert(pThis->PciDev.config[0x3d] == 0x01);
+                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x14] == 0x01); Assert(pThis->PciDev.abConfig[0x15] == 0x00); Assert(pThis->PciDev.abConfig[0x16] == 0x00); Assert(pThis->PciDev.abConfig[0x17] == 0x00);
+    PCIDevSetInterruptLine    (&pThis->PciDev, 0x00);   /* 3c rw. */                       Assert(pThis->PciDev.abConfig[0x3c] == 0x00);
+    PCIDevSetInterruptPin     (&pThis->PciDev, 0x01);   /* 3d ro - INTA#. */               Assert(pThis->PciDev.abConfig[0x3d] == 0x01);
 
     if (pThis->uCodecModel == AC97_CODEC_AD1980)
     {
diff --git a/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp b/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
index 05fccc7..7385349 100644
--- a/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
@@ -1005,7 +1005,7 @@ int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRe
             break;
 
         /* Copy the data from our ring buffer to the core audio buffer. */
-        memcpy((UInt8 *)pvDst + cbWritten, pvSrc + cbWritten, cbToWrite);
+        memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite);
 
         /* Release the read buffer, so it could be used for new data. */
         RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);
diff --git a/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp b/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
index 6b3d2f2..d234b14 100644
--- a/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
@@ -87,7 +87,7 @@ typedef struct DRVHOSTPULSEAUDIO
     */
     pa_context           *pContext;
     /** Shutdown indicator. */
-    bool                  fLoopWait;
+    volatile bool         fAbortLoop;
     /** Pointer to host audio interface. */
     PDMIHOSTAUDIO         IHostAudio;
     /** Error count for not flooding the release log.
@@ -177,7 +177,7 @@ static void paSignalWaiter(PDRVHOSTPULSEAUDIO pThis)
     if (!pThis)
         return;
 
-    pThis->fLoopWait = true;
+    pThis->fAbortLoop = true;
     pa_threaded_mainloop_signal(pThis->pMainLoop, 0);
 }
 
@@ -261,12 +261,12 @@ static int paWaitForEx(PDRVHOSTPULSEAUDIO pThis, pa_operation *pOP, RTMSINTERVAL
     uint64_t u64StartMs = RTTimeMilliTS();
     while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING)
     {
-        if (!pThis->fLoopWait)
+        if (!pThis->fAbortLoop)
         {
             AssertPtr(pThis->pMainLoop);
             pa_threaded_mainloop_wait(pThis->pMainLoop);
         }
-        pThis->fLoopWait = false;
+        pThis->fAbortLoop = false;
 
         uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
         if (u64ElapsedMs >= cMsTimeout)
@@ -467,9 +467,9 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
         /* Wait until the stream is ready. */
         for (;;)
         {
-            if (!pThis->fLoopWait)
+            if (!pThis->fAbortLoop)
                 pa_threaded_mainloop_wait(pThis->pMainLoop);
-            pThis->fLoopWait = false;
+            pThis->fAbortLoop = false;
 
             pa_stream_state_t streamSt = pa_stream_get_state(pStream);
             if (streamSt == PA_STREAM_READY)
@@ -537,7 +537,7 @@ static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
         return rc;
     }
 
-    pThis->fLoopWait = false;
+    pThis->fAbortLoop = false;
     pThis->pMainLoop = NULL;
 
     bool fLocked = false;
@@ -586,9 +586,9 @@ static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
         /* Wait until the pThis->pContext is ready. */
         for (;;)
         {
-            if (!pThis->fLoopWait)
+            if (!pThis->fAbortLoop)
                 pa_threaded_mainloop_wait(pThis->pMainLoop);
-            pThis->fLoopWait = false;
+            pThis->fAbortLoop = false;
 
             pa_context_state_t cstate = pa_context_get_state(pThis->pContext);
             if (cstate == PA_CONTEXT_READY)
diff --git a/src/VBox/Devices/Audio/DevIchHdaCodec.cpp b/src/VBox/Devices/Audio/HDACodec.cpp
similarity index 99%
copy from src/VBox/Devices/Audio/DevIchHdaCodec.cpp
copy to src/VBox/Devices/Audio/HDACodec.cpp
index 4231f5c..7e05c0f 100644
--- a/src/VBox/Devices/Audio/DevIchHdaCodec.cpp
+++ b/src/VBox/Devices/Audio/HDACodec.cpp
@@ -1,4 +1,4 @@
-/* $Id: DevIchHdaCodec.cpp $ */
+/* $Id: HDACodec.cpp $ */
 /** @file
  * DevIchHdaCodec - VBox ICH Intel HD Audio Codec.
  *
@@ -35,8 +35,8 @@
 
 #include "VBoxDD.h"
 #include "DrvAudio.h"
-#include "DevIchHdaCodec.h"
-#include "DevIchHdaCommon.h"
+#include "HDACodec.h"
+#include "DevHDACommon.h"
 #include "AudioMixer.h"
 
 
diff --git a/src/VBox/Devices/Audio/DevIchHdaCodec.h b/src/VBox/Devices/Audio/HDACodec.h
similarity index 99%
copy from src/VBox/Devices/Audio/DevIchHdaCodec.h
copy to src/VBox/Devices/Audio/HDACodec.h
index 2e1a997..24e545f 100644
--- a/src/VBox/Devices/Audio/DevIchHdaCodec.h
+++ b/src/VBox/Devices/Audio/HDACodec.h
@@ -1,4 +1,4 @@
-/* $Id: DevIchHdaCodec.h $ */
+/* $Id: HDACodec.h $ */
 /** @file
  * DevIchHdaCodec - VBox ICH Intel HD Audio Codec.
  */
diff --git a/src/VBox/Devices/Audio/alsa_stubs.c b/src/VBox/Devices/Audio/alsa_stubs.c
index fbed735..d59f2e7 100644
--- a/src/VBox/Devices/Audio/alsa_stubs.c
+++ b/src/VBox/Devices/Audio/alsa_stubs.c
@@ -39,7 +39,7 @@ PROXY_STUB(snd_device_name_hint, int,
            (int card, const char *iface, void ***hints),
            (card, iface, hints))
 PROXY_STUB(snd_device_name_free_hint, int,
-           (void ***hints),
+           (void **hints),
            (hints))
 PROXY_STUB(snd_device_name_get_hint, char *,
            (const void *hint, const char *id),
diff --git a/src/VBox/Devices/Audio/pulse_stubs.c b/src/VBox/Devices/Audio/pulse_stubs.c
index 7464ee2..f4af6ab 100644
--- a/src/VBox/Devices/Audio/pulse_stubs.c
+++ b/src/VBox/Devices/Audio/pulse_stubs.c
@@ -116,8 +116,8 @@ PROXY_STUB_VOID(pa_context_disconnect,
                 (pa_context *c),
                 (c))
 PROXY_STUB     (pa_context_get_server_info, pa_operation*,
-                (pa_context *c, const char *name, pa_server_info_cb_t cb, void *userdata),
-                (c, name, cb, userdata))
+                (pa_context *c, pa_server_info_cb_t cb, void *userdata),
+                (c, cb, userdata))
 PROXY_STUB     (pa_context_get_sink_info_by_name, pa_operation*,
                 (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata),
                 (c, name, cb, userdata))
diff --git a/src/VBox/Devices/Audio_50/AudioMixBuffer.cpp b/src/VBox/Devices/Audio_50/AudioMixBuffer.cpp
new file mode 100644
index 0000000..0528dc2
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/AudioMixBuffer.cpp
@@ -0,0 +1,1756 @@
+/* $Id: AudioMixBuffer.cpp $ */
+/** @file
+ * VBox audio: Audio mixing buffer for converting reading/writing audio
+ *             samples.
+ */
+
+/*
+ * Copyright (C) 2014-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER
+#include <VBox/log.h>
+
+/*
+ * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
+ * to a file on the host. Be sure to adjust DEBUG_DUMP_PCM_DATA_PATH
+ * to your needs before using this!
+ */
+#if 0
+# define DEBUG_DUMP_PCM_DATA
+# ifdef RT_OS_WINDOWS
+#  define DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# else
+#  define DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+# endif
+#endif
+
+#include <iprt/asm-math.h>
+#include <iprt/assert.h>
+#ifdef DEBUG_DUMP_PCM_DATA
+# include <iprt/file.h>
+#endif
+#include <iprt/mem.h>
+#include <iprt/string.h> /* For RT_BZERO. */
+
+#ifdef TESTCASE
+# define LOG_ENABLED
+# include <iprt/stream.h>
+#endif
+#include <VBox/err.h>
+
+#include "AudioMixBuffer.h"
+
+#if 0
+# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
+#else
+# if defined(TESTCASE)
+#  define AUDMIXBUF_LOG(x) LogFunc(x)
+# else
+#  define AUDMIXBUF_LOG(x) do {} while (0)
+# endif
+#endif
+
+
+/*
+ *   Soft Volume Control
+ *
+ * The external code supplies an 8-bit volume (attenuation) value in the
+ * 0 .. 255 range. This represents 0 to -96dB attenuation where an input
+ * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
+ *
+ * Each step thus correspons to 96 / 256 or 0.375dB. Every 6dB (16 steps)
+ * represents doubling the sample value.
+ *
+ * For internal use, the volume control needs to be converted to a 16-bit
+ * (sort of) exponential value between 1 and 65536. This is used with fixed
+ * point arithmetic such that 65536 means 1.0 and 1 means 1/65536.
+ *
+ * For actual volume calculation, 33.31 fixed point is used. Maximum (or
+ * unattenuated) volume is represented as 0x40000000; conveniently, this
+ * value fits into a uint32_t.
+ *
+ * To enable fast processing, the maximum volume must be a power of two
+ * and must not have a sign when converted to int32_t. While 0x80000000
+ * violates these constraints, 0x40000000 does not.
+ */
+
+
+/** Logarithmic/exponential volume conversion table. */
+static uint32_t s_aVolumeConv[256] = {
+        1,     1,     1,     1,     1,     1,     1,     1, /*   7 */
+        1,     2,     2,     2,     2,     2,     2,     2, /*  15 */
+        2,     2,     2,     2,     2,     3,     3,     3, /*  23 */
+        3,     3,     3,     3,     4,     4,     4,     4, /*  31 */
+        4,     4,     5,     5,     5,     5,     5,     6, /*  39 */
+        6,     6,     6,     7,     7,     7,     8,     8, /*  47 */
+        8,     9,     9,    10,    10,    10,    11,    11, /*  55 */
+       12,    12,    13,    13,    14,    15,    15,    16, /*  63 */
+       17,    17,    18,    19,    20,    21,    22,    23, /*  71 */
+       24,    25,    26,    27,    28,    29,    31,    32, /*  79 */
+       33,    35,    36,    38,    40,    41,    43,    45, /*  87 */
+       47,    49,    52,    54,    56,    59,    61,    64, /*  95 */
+       67,    70,    73,    76,    79,    83,    87,    91, /* 103 */
+       95,    99,   103,   108,   112,   117,   123,   128, /* 111 */
+      134,   140,   146,   152,   159,   166,   173,   181, /* 119 */
+      189,   197,   206,   215,   225,   235,   245,   256, /* 127 */
+      267,   279,   292,   304,   318,   332,   347,   362, /* 135 */
+      378,   395,   412,   431,   450,   470,   490,   512, /* 143 */
+      535,   558,   583,   609,   636,   664,   693,   724, /* 151 */
+      756,   790,   825,   861,   899,   939,   981,  1024, /* 159 */
+     1069,  1117,  1166,  1218,  1272,  1328,  1387,  1448, /* 167 */
+     1512,  1579,  1649,  1722,  1798,  1878,  1961,  2048, /* 175 */
+     2139,  2233,  2332,  2435,  2543,  2656,  2774,  2896, /* 183 */
+     3025,  3158,  3298,  3444,  3597,  3756,  3922,  4096, /* 191 */
+     4277,  4467,  4664,  4871,  5087,  5312,  5547,  5793, /* 199 */
+     6049,  6317,  6597,  6889,  7194,  7512,  7845,  8192, /* 207 */
+     8555,  8933,  9329,  9742, 10173, 10624, 11094, 11585, /* 215 */
+    12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, /* 223 */
+    17109, 17867, 18658, 19484, 20347, 21247, 22188, 23170, /* 231 */
+    24196, 25268, 26386, 27554, 28774, 30048, 31379, 32768, /* 239 */
+    34219, 35734, 37316, 38968, 40693, 42495, 44376, 46341, /* 247 */
+    48393, 50535, 52773, 55109, 57549, 60097, 62757, 65536, /* 255 */
+};
+
+/* Bit shift for fixed point conversion. */
+#define AUDIOMIXBUF_VOL_SHIFT       30
+
+/* Internal representation of 0dB volume (1.0 in fixed point). */
+#define AUDIOMIXBUF_VOL_0DB         (1 << AUDIOMIXBUF_VOL_SHIFT)
+
+AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000);   /* Must always hold. */
+AssertCompile(AUDIOMIXBUF_VOL_0DB == 0x40000000);   /* For now -- when only attenuation is used. */
+
+/**
+ * Structure for holding sample conversion parameters for
+ * the audioMixBufConvFromXXX / audioMixBufConvToXXX macros.
+ */
+typedef struct AUDMIXBUF_CONVOPTS
+{
+    /** Number of audio samples to convert. */
+    uint32_t       cSamples;
+    /** Volume to apply during conversion. Pass 0
+     *  to convert the original values. May not apply to
+     *  all conversion functions. */
+    PDMAUDIOVOLUME Volume;
+} AUDMIXBUF_CONVOPTS, *PAUDMIXBUF_CONVOPTS;
+
+/*
+ * When running the audio testcases we want to verfiy
+ * the macro-generated routines separately, so unmark them as being
+ * inlined + static.
+ */
+#ifdef TESTCASE
+# define AUDMIXBUF_MACRO_FN
+#else
+# define AUDMIXBUF_MACRO_FN static inline
+#endif
+
+#ifdef DEBUG
+static uint64_t s_cSamplesMixedTotal = 0;
+static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf);
+#endif
+
+typedef uint32_t (AUDMIXBUF_FN_CONVFROM) (PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, const PAUDMIXBUF_CONVOPTS pOpts);
+typedef AUDMIXBUF_FN_CONVFROM *PAUDMIXBUF_FN_CONVFROM;
+
+typedef void (AUDMIXBUF_FN_CONVTO) (void *pvDst, const PPDMAUDIOSAMPLE paSrc, const PAUDMIXBUF_CONVOPTS pOpts);
+typedef AUDMIXBUF_FN_CONVTO *PAUDMIXBUF_FN_CONVTO;
+
+/* Can return VINF_TRY_AGAIN for getting next pointer at beginning (circular) */
+
+/**
+ * Acquires (reads) a mutable pointer to the mixing buffer's audio samples without
+ * any conversion done.
+ ** @todo Rename to AudioMixBufPeek(Mutable/Raw)?
+ ** @todo Protect the buffer's data?
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to acquire audio samples from.
+ * @param   cSamplesToRead          Number of audio samples to read.
+ * @param   ppvSamples              Returns a mutable pointer to the buffer's audio sample data.
+ * @param   pcSamplesRead           Number of audio samples read (acquired).
+ *
+ * @remark  This function is not thread safe!
+ */
+int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead,
+                       PPDMAUDIOSAMPLE *ppvSamples, uint32_t *pcSamplesRead)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(ppvSamples, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcSamplesRead, VERR_INVALID_POINTER);
+
+    int rc;
+
+    if (!cSamplesToRead)
+    {
+        *pcSamplesRead = 0;
+        return VINF_SUCCESS;
+    }
+
+    uint32_t cSamplesRead;
+    if (pMixBuf->offReadWrite + cSamplesToRead > pMixBuf->cSamples)
+    {
+        cSamplesRead = pMixBuf->cSamples - pMixBuf->offReadWrite;
+        rc = VINF_TRY_AGAIN;
+    }
+    else
+    {
+        cSamplesRead = cSamplesToRead;
+        rc = VINF_SUCCESS;
+    }
+
+    *ppvSamples = &pMixBuf->pSamples[pMixBuf->offReadWrite];
+    AssertPtr(ppvSamples);
+
+    pMixBuf->offReadWrite = (pMixBuf->offReadWrite + cSamplesRead) % pMixBuf->cSamples;
+    Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
+    pMixBuf->cProcessed -= RT_MIN(cSamplesRead, pMixBuf->cProcessed);
+
+    *pcSamplesRead = cSamplesRead;
+
+    return rc;
+}
+
+/**
+ * Returns available number of samples for reading.
+ *
+ * @return  uint32_t                Number of samples available for reading.
+ * @param   pMixBuf                 Mixing buffer to return value for.
+ */
+uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, true);
+
+    uint32_t cAvail;
+    if (pMixBuf->pParent) /* Child */
+        cAvail = pMixBuf->cMixed;
+    else
+        cAvail = pMixBuf->cProcessed;
+
+    Assert(cAvail <= pMixBuf->cSamples);
+    return cAvail;
+}
+
+/**
+ * Clears the entire sample buffer.
+ *
+ * @param   pMixBuf                 Mixing buffer to clear.
+ *
+ */
+void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturnVoid(pMixBuf);
+
+    if (pMixBuf->cSamples)
+        RT_BZERO(pMixBuf->pSamples, pMixBuf->cSamples * sizeof(PDMAUDIOSAMPLE));
+}
+
+/**
+ * Clears (zeroes) the buffer by a certain amount of (processed) samples and
+ * keeps track to eventually assigned children buffers.
+ *
+ * @param   pMixBuf                 Mixing buffer to clear.
+ * @param   cSamplesToClear         Number of audio samples to clear.
+ */
+void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear)
+{
+    AUDMIXBUF_LOG(("cSamples=%RU32\n", cSamplesToClear));
+    AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32\n",
+                   pMixBuf->pszName, pMixBuf->offReadWrite, pMixBuf->cProcessed));
+
+    PPDMAUDIOMIXBUF pIter;
+    RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
+    {
+        AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",
+                       pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
+
+        pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear);
+        pIter->offReadWrite = 0;
+    }
+
+    uint32_t cLeft = RT_MIN(cSamplesToClear, pMixBuf->cSamples);
+    uint32_t offClear;
+
+    if (cLeft > pMixBuf->offReadWrite) /* Zero end of buffer first (wrap-around). */
+    {
+        AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n",
+                       (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
+                        pMixBuf->cSamples));
+
+        RT_BZERO(pMixBuf->pSamples + (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
+                 (cLeft - pMixBuf->offReadWrite) * sizeof(PDMAUDIOSAMPLE));
+
+        cLeft -= cLeft - pMixBuf->offReadWrite;
+        offClear = 0;
+    }
+    else
+        offClear = pMixBuf->offReadWrite - cLeft;
+
+    if (cLeft)
+    {
+        AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n",
+                       offClear, offClear + cLeft));
+        RT_BZERO(pMixBuf->pSamples + offClear, cLeft * sizeof(PDMAUDIOSAMPLE));
+    }
+}
+
+/**
+ * Destroys (uninitializes) a mixing buffer.
+ *
+ * @param   pMixBuf                 Mixing buffer to destroy.
+ */
+void AudioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf)
+{
+    if (!pMixBuf)
+        return;
+
+    AudioMixBufUnlink(pMixBuf);
+
+    if (pMixBuf->pszName)
+    {
+        AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
+
+        RTStrFree(pMixBuf->pszName);
+        pMixBuf->pszName = NULL;
+    }
+
+    if (pMixBuf->pRate)
+    {
+        RTMemFree(pMixBuf->pRate);
+        pMixBuf->pRate = NULL;
+    }
+
+    if (pMixBuf->pSamples)
+    {
+        Assert(pMixBuf->cSamples);
+
+        RTMemFree(pMixBuf->pSamples);
+        pMixBuf->pSamples = NULL;
+    }
+
+    pMixBuf->cSamples = 0;
+}
+
+/**
+ * Returns the size (in audio samples) of free audio buffer space.
+ *
+ * @return  uint32_t                Size (in audio samples) of free audio buffer space.
+ * @param   pMixBuf                 Mixing buffer to return free size for.
+ */
+uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, 0);
+
+    uint32_t cSamplesFree;
+    if (pMixBuf->pParent)
+    {
+        /*
+         * As a linked child buffer we want to know how many samples
+         * already have been consumed by the parent.
+         */
+        Assert(pMixBuf->cMixed <= pMixBuf->pParent->cSamples);
+        cSamplesFree = pMixBuf->pParent->cSamples - pMixBuf->cMixed;
+    }
+    else /* As a parent. */
+    {
+        Assert(pMixBuf->cSamples >= pMixBuf->cProcessed);
+        cSamplesFree = pMixBuf->cSamples - pMixBuf->cProcessed;
+    }
+
+    AUDMIXBUF_LOG(("%s: cSamplesFree=%RU32\n", pMixBuf->pszName, cSamplesFree));
+    return cSamplesFree;
+}
+
+/**
+ * Returns the size (in bytes) of free audio buffer space.
+ *
+ * @return  uint32_t                Size (in bytes) of free audio buffer space.
+ * @param   pMixBuf                 Mixing buffer to return free size for.
+ */
+uint32_t AudioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf)
+{
+    return AUDIOMIXBUF_S2B(pMixBuf, AudioMixBufFree(pMixBuf));
+}
+
+/**
+ * Allocates the internal audio sample buffer.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to allocate sample buffer for.
+ * @param   cSamples                Number of audio samples to allocate.
+ */
+static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertReturn(cSamples, VERR_INVALID_PARAMETER);
+
+    AUDMIXBUF_LOG(("%s: cSamples=%RU32\n", pMixBuf->pszName, cSamples));
+
+    size_t cbSamples = cSamples * sizeof(PDMAUDIOSAMPLE);
+    if (!cbSamples)
+        return VERR_INVALID_PARAMETER;
+
+    pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemAllocZ(cbSamples);
+    if (!pMixBuf->pSamples)
+        return VERR_NO_MEMORY;
+
+    pMixBuf->cSamples = cSamples;
+
+    return VINF_SUCCESS;
+}
+
+/** Note: Enabling this will generate huge logs! */
+//#define DEBUG_MACROS
+
+#ifdef DEBUG_MACROS
+# define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
+#elif defined(TESTCASE)
+# define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
+#else
+# define AUDMIXBUF_MACRO_LOG(x) do {} while (0)
+#endif
+
+/**
+ * Macro for generating the conversion routines from/to different formats.
+ * Be careful what to pass in/out, as most of the macros are optimized for speed and
+ * thus don't do any bounds checking!
+ *
+ * Note: Currently does not handle any endianness conversion yet!
+ */
+#define AUDMIXBUF_CONVERT(_aName, _aType, _aMin, _aMax, _aSigned, _aShift) \
+    /* Clips a specific output value to a single sample value. */ \
+    AUDMIXBUF_MACRO_FN int64_t audioMixBufClipFrom##_aName(_aType aVal) \
+    { \
+        if (_aSigned) \
+            return ((int64_t) aVal) << (32 - _aShift); \
+        return ((int64_t) aVal - ((_aMax >> 1) + 1)) << (32 - _aShift); \
+    } \
+    \
+    /* Clips a single sample value to a specific output value. */ \
+    AUDMIXBUF_MACRO_FN _aType audioMixBufClipTo##_aName(int64_t iVal) \
+    { \
+        if (iVal >= 0x7fffffff) \
+            return _aMax; \
+        else if (iVal < -INT64_C(0x80000000)) \
+            return _aMin; \
+        \
+        if (_aSigned) \
+            return (_aType) (iVal >> (32 - _aShift)); \
+        return ((_aType) ((iVal >> (32 - _aShift)) + ((_aMax >> 1) + 1))); \
+    } \
+    \
+    AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFrom##_aName##Stereo(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
+                                                                    const PAUDMIXBUF_CONVOPTS pOpts) \
+    { \
+        _aType *pSrc = (_aType *)pvSrc; \
+        uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
+        AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, sizeof(%zu), lVol=%RU32, rVol=%RU32\n", \
+                             pOpts->cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
+        for (uint32_t i = 0; i < cSamples; i++) \
+        { \
+            AUDMIXBUF_MACRO_LOG(("%p: l=%RI16, r=%RI16\n", paDst, *pSrc, *(pSrc + 1))); \
+            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
+            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
+            AUDMIXBUF_MACRO_LOG(("\t-> l=%RI64, r=%RI64\n", paDst->i64LSample, paDst->i64RSample)); \
+            paDst++; \
+        } \
+        \
+        return cSamples; \
+    } \
+    \
+    AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFrom##_aName##Mono(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
+                                                                  const PAUDMIXBUF_CONVOPTS pOpts) \
+    { \
+        _aType *pSrc = (_aType *)pvSrc; \
+        uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
+        AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, sizeof(%zu), lVol=%RU32, rVol=%RU32\n", \
+                             cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
+        for (uint32_t i = 0; i < cSamples; i++) \
+        { \
+            AUDMIXBUF_MACRO_LOG(("%p: s=%RI16\n", paDst, *pSrc)); \
+            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uLeft)  >> AUDIOMIXBUF_VOL_SHIFT; \
+            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
+            ++pSrc; \
+            AUDMIXBUF_MACRO_LOG(("\t-> l=%RI64, r=%RI64\n", paDst->i64LSample, paDst->i64RSample)); \
+            paDst++; \
+        } \
+        \
+        return cSamples; \
+    } \
+    \
+    AUDMIXBUF_MACRO_FN void audioMixBufConvTo##_aName##Stereo(void *pvDst, const PPDMAUDIOSAMPLE paSrc, \
+                                                              const PAUDMIXBUF_CONVOPTS pOpts) \
+    { \
+        PPDMAUDIOSAMPLE pSrc = paSrc; \
+        _aType *pDst = (_aType *)pvDst; \
+        _aType l, r; \
+        uint32_t cSamples = pOpts->cSamples; \
+        while (cSamples--) \
+        { \
+            AUDMIXBUF_MACRO_LOG(("%p: l=%RI64, r=%RI64\n", pSrc, pSrc->i64LSample, pSrc->i64RSample)); \
+            l = audioMixBufClipTo##_aName(pSrc->i64LSample); \
+            r = audioMixBufClipTo##_aName(pSrc->i64RSample); \
+            AUDMIXBUF_MACRO_LOG(("\t-> l=%RI16, r=%RI16\n", l, r)); \
+            *pDst++ = l; \
+            *pDst++ = r; \
+            pSrc++; \
+        } \
+    } \
+    \
+    AUDMIXBUF_MACRO_FN void audioMixBufConvTo##_aName##Mono(void *pvDst, const PPDMAUDIOSAMPLE paSrc, \
+                                                            const PAUDMIXBUF_CONVOPTS pOpts) \
+    { \
+        PPDMAUDIOSAMPLE pSrc = paSrc; \
+        _aType *pDst = (_aType *)pvDst; \
+        uint32_t cSamples = pOpts->cSamples; \
+        while (cSamples--) \
+        { \
+            *pDst++ = audioMixBufClipTo##_aName((pSrc->i64LSample + pSrc->i64RSample) / 2); \
+            pSrc++; \
+        } \
+    }
+
+/* audioMixBufConvXXXS8: 8 bit, signed. */
+AUDMIXBUF_CONVERT(S8 /* Name */,  int8_t,   INT8_MIN  /* Min */, INT8_MAX   /* Max */, true  /* fSigned */, 8  /* cShift */)
+/* audioMixBufConvXXXU8: 8 bit, unsigned. */
+AUDMIXBUF_CONVERT(U8 /* Name */,  uint8_t,  0         /* Min */, UINT8_MAX  /* Max */, false /* fSigned */, 8  /* cShift */)
+/* audioMixBufConvXXXS16: 16 bit, signed. */
+AUDMIXBUF_CONVERT(S16 /* Name */, int16_t,  INT16_MIN /* Min */, INT16_MAX  /* Max */, true  /* fSigned */, 16 /* cShift */)
+/* audioMixBufConvXXXU16: 16 bit, unsigned. */
+AUDMIXBUF_CONVERT(U16 /* Name */, uint16_t, 0         /* Min */, UINT16_MAX /* Max */, false /* fSigned */, 16 /* cShift */)
+/* audioMixBufConvXXXS32: 32 bit, signed. */
+AUDMIXBUF_CONVERT(S32 /* Name */, int32_t,  INT32_MIN /* Min */, INT32_MAX  /* Max */, true  /* fSigned */, 32 /* cShift */)
+/* audioMixBufConvXXXU32: 32 bit, unsigned. */
+AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0         /* Min */, UINT32_MAX /* Max */, false /* fSigned */, 32 /* cShift */)
+
+#undef AUDMIXBUF_CONVERT
+
+#define AUDMIXBUF_MIXOP(_aName, _aOp) \
+    AUDMIXBUF_MACRO_FN void audioMixBufOp##_aName(PPDMAUDIOSAMPLE paDst, uint32_t cDstSamples, \
+                                                  PPDMAUDIOSAMPLE paSrc, uint32_t cSrcSamples, \
+                                                  PPDMAUDIOSTRMRATE pRate, \
+                                                  uint32_t *pcDstWritten, uint32_t *pcSrcRead) \
+    { \
+        AUDMIXBUF_MACRO_LOG(("cSrcSamples=%RU32, cDstSamples=%RU32\n", cSrcSamples, cDstSamples)); \
+        AUDMIXBUF_MACRO_LOG(("pRate=%p: srcOffset=0x%RX32 (%RU32), dstOffset=0x%RX32 (%RU32), dstInc=0x%RX64 (%RU64)\n", \
+                             pRate, pRate->srcOffset, pRate->srcOffset, \
+                             (uint32_t)(pRate->dstOffset >> 32), (uint32_t)(pRate->dstOffset >> 32), \
+                             pRate->dstInc, pRate->dstInc)); \
+        \
+        if (pRate->dstInc == (UINT64_C(1) + UINT32_MAX)) /* No conversion needed? */ \
+        { \
+            uint32_t cSamples = RT_MIN(cSrcSamples, cDstSamples); \
+            AUDMIXBUF_MACRO_LOG(("cSamples=%RU32\n", cSamples)); \
+            for (uint32_t i = 0; i < cSamples; i++) \
+            { \
+                paDst[i].i64LSample _aOp paSrc[i].i64LSample; \
+                paDst[i].i64RSample _aOp paSrc[i].i64RSample; \
+            } \
+            \
+            if (pcDstWritten) \
+                *pcDstWritten = cSamples; \
+            if (pcSrcRead) \
+                *pcSrcRead = cSamples; \
+            return; \
+        } \
+        \
+        PPDMAUDIOSAMPLE paSrcStart = paSrc; \
+        PPDMAUDIOSAMPLE paSrcEnd   = paSrc + cSrcSamples; \
+        PPDMAUDIOSAMPLE paDstStart = paDst; \
+        PPDMAUDIOSAMPLE paDstEnd   = paDst + cDstSamples; \
+        PDMAUDIOSAMPLE  samCur = { 0 }; \
+        PDMAUDIOSAMPLE  samOut; \
+        PDMAUDIOSAMPLE  samLast    = pRate->srcSampleLast; \
+        uint64_t        lDelta = 0; \
+        \
+        AUDMIXBUF_MACRO_LOG(("Start: paDstEnd=%p - paDstStart=%p -> %zu\n", paDstEnd, paDst, paDstEnd - paDstStart)); \
+        AUDMIXBUF_MACRO_LOG(("Start: paSrcEnd=%p - paSrcStart=%p -> %zu\n", paSrcEnd, paSrc, paSrcEnd - paSrcStart)); \
+        \
+        while (paDst < paDstEnd) \
+        { \
+            Assert(paSrc <= paSrcEnd); \
+            Assert(paDst <= paDstEnd); \
+            if (paSrc == paSrcEnd) \
+                break; \
+            \
+            lDelta = 0; \
+            while (pRate->srcOffset <= (pRate->dstOffset >> 32)) \
+            { \
+                Assert(paSrc <= paSrcEnd); \
+                samLast = *paSrc++; \
+                pRate->srcOffset++; \
+                lDelta++; \
+                if (paSrc == paSrcEnd) \
+                    break; \
+            } \
+            \
+            Assert(paSrc <= paSrcEnd); \
+            if (paSrc == paSrcEnd) \
+                break; \
+            \
+            samCur = *paSrc; \
+            \
+            /* Interpolate. */ \
+            int64_t iDstOffInt = pRate->dstOffset & UINT32_MAX; \
+            \
+            samOut.i64LSample = (samLast.i64LSample * ((int64_t) (INT64_C(1) << 32) - iDstOffInt) + samCur.i64LSample * iDstOffInt) >> 32; \
+            samOut.i64RSample = (samLast.i64RSample * ((int64_t) (INT64_C(1) << 32) - iDstOffInt) + samCur.i64RSample * iDstOffInt) >> 32; \
+            \
+            paDst->i64LSample _aOp samOut.i64LSample; \
+            paDst->i64RSample _aOp samOut.i64RSample; \
+            \
+            AUDMIXBUF_MACRO_LOG(("\tlDelta=0x%RX64 (%RU64), iDstOffInt=0x%RX64 (%RI64), l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64)\n", \
+                                 lDelta, lDelta, iDstOffInt, iDstOffInt, \
+                                 paDst->i64LSample, paDst->i64RSample, \
+                                 samCur.i64LSample, samCur.i64RSample)); \
+            \
+            paDst++; \
+            pRate->dstOffset += pRate->dstInc; \
+            \
+            AUDMIXBUF_MACRO_LOG(("\t\tpRate->dstOffset=0x%RX32 (%RU32)\n", pRate->dstOffset, pRate->dstOffset >> 32)); \
+            \
+        } \
+        \
+        AUDMIXBUF_MACRO_LOG(("End: paDst=%p - paDstStart=%p -> %zu\n", paDst, paDstStart, paDst - paDstStart)); \
+        AUDMIXBUF_MACRO_LOG(("End: paSrc=%p - paSrcStart=%p -> %zu\n", paSrc, paSrcStart, paSrc - paSrcStart)); \
+        \
+        pRate->srcSampleLast = samLast; \
+        \
+        AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64, lDelta=0x%RX64 (%RU64)\n", \
+                              pRate->srcSampleLast.i64LSample, pRate->srcSampleLast.i64RSample, lDelta, lDelta)); \
+        \
+        if (pcDstWritten) \
+            *pcDstWritten = paDst - paDstStart; \
+        if (pcSrcRead) \
+            *pcSrcRead = paSrc - paSrcStart; \
+    }
+
+#if 0 // unused
+/* audioMixBufOpAssign: Assigns values from source buffer to destination bufffer, overwriting the destination. */
+AUDMIXBUF_MIXOP(Assign /* Name */,  = /* Operation */)
+#endif
+/* audioMixBufOpBlend: Blends together the values from both, the source and the destination buffer. */
+AUDMIXBUF_MIXOP(Blend  /* Name */, += /* Operation */)
+
+#undef AUDMIXBUF_MIXOP
+#undef AUDMIXBUF_MACRO_LOG
+
+/** Dummy conversion used when the source is muted. */
+AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFromSilence(PPDMAUDIOSAMPLE paDst, const void *pvSrc,
+                                                       uint32_t cbSrc, const PAUDMIXBUF_CONVOPTS pOpts)
+{
+    RT_NOREF(cbSrc, pvSrc);
+    /* Internally zero always corresponds to silence. */
+    memset(paDst, 0, pOpts->cSamples * sizeof(paDst[0]));
+    return pOpts->cSamples;
+}
+
+/**
+ * Looks up the matching conversion (macro) routine for converting
+ * audio samples from a source format.
+ *
+ ** @todo Speed up the lookup by binding it to the actual stream state.
+ *
+ * @return  PAUDMIXBUF_FN_CONVFROM  Function pointer to conversion macro if found, NULL if not supported.
+ * @param   enmFmt                  Audio format to lookup conversion macro for.
+ * @param   fMuted                  Flag determining whether the source is muted.
+ */
+static inline PAUDMIXBUF_FN_CONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enmFmt, bool fMuted)
+{
+    if (fMuted)
+        return audioMixBufConvFromSilence;
+
+    if (AUDMIXBUF_FMT_SIGNED(enmFmt))
+    {
+        if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvFromS8Stereo;
+                case 16: return audioMixBufConvFromS16Stereo;
+                case 32: return audioMixBufConvFromS32Stereo;
+                default: return NULL;
+            }
+        }
+        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvFromS8Mono;
+                case 16: return audioMixBufConvFromS16Mono;
+                case 32: return audioMixBufConvFromS32Mono;
+                default: return NULL;
+            }
+        }
+    }
+    else /* Unsigned */
+    {
+        if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvFromU8Stereo;
+                case 16: return audioMixBufConvFromU16Stereo;
+                case 32: return audioMixBufConvFromU32Stereo;
+                default: return NULL;
+            }
+        }
+        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvFromU8Mono;
+                case 16: return audioMixBufConvFromU16Mono;
+                case 32: return audioMixBufConvFromU32Mono;
+                default: return NULL;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Looks up the matching conversion (macro) routine for converting
+ * audio samples to a destination format.
+ *
+ ** @todo Speed up the lookup by binding it to the actual stream state.
+ *
+ * @return  PAUDMIXBUF_FN_CONVTO    Function pointer to conversion macro if found, NULL if not supported.
+ * @param   enmFmt                  Audio format to lookup conversion macro for.
+ */
+static inline PAUDMIXBUF_FN_CONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
+{
+    if (AUDMIXBUF_FMT_SIGNED(enmFmt))
+    {
+        if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvToS8Stereo;
+                case 16: return audioMixBufConvToS16Stereo;
+                case 32: return audioMixBufConvToS32Stereo;
+                default: return NULL;
+            }
+        }
+        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvToS8Mono;
+                case 16: return audioMixBufConvToS16Mono;
+                case 32: return audioMixBufConvToS32Mono;
+                default: return NULL;
+            }
+        }
+    }
+    else /* Unsigned */
+    {
+        if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvToU8Stereo;
+                case 16: return audioMixBufConvToU16Stereo;
+                case 32: return audioMixBufConvToU32Stereo;
+                default: return NULL;
+            }
+        }
+        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        {
+            switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
+            {
+                case 8:  return audioMixBufConvToU8Mono;
+                case 16: return audioMixBufConvToU16Mono;
+                case 32: return audioMixBufConvToU32Mono;
+                default: return NULL;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Initializes a mixing buffer.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to initialize.
+ * @param   pszName                 Name of mixing buffer for easier identification. Optional.
+ * @param   pProps                  PCM audio properties to use for the mixing buffer.
+ * @param   cSamples                Maximum number of audio samples the mixing buffer can hold.
+ */
+int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMPCMPROPS pProps, uint32_t cSamples)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pProps,  VERR_INVALID_POINTER);
+
+    pMixBuf->pParent = NULL;
+    RTListInit(&pMixBuf->lstBuffers);
+
+    pMixBuf->pSamples = NULL;
+    pMixBuf->cSamples = 0;
+
+    pMixBuf->offReadWrite = 0;
+    pMixBuf->cMixed       = 0;
+    pMixBuf->cProcessed   = 0;
+
+    /* Set initial volume to max. */
+    pMixBuf->Volume.fMuted = false;
+    pMixBuf->Volume.uLeft  = AUDIOMIXBUF_VOL_0DB;
+    pMixBuf->Volume.uRight = AUDIOMIXBUF_VOL_0DB;
+
+    /* Prevent division by zero.
+     * Do a 1:1 conversion according to AUDIOMIXBUF_S2B_RATIO. */
+    pMixBuf->iFreqRatio = 1 << 20;
+
+    pMixBuf->pRate = NULL;
+
+    pMixBuf->AudioFmt = AUDMIXBUF_AUDIO_FMT_MAKE(pProps->uHz,
+                                                 pProps->cChannels,
+                                                 pProps->cBits,
+                                                 pProps->fSigned);
+    pMixBuf->cShift = pProps->cShift;
+    pMixBuf->pszName = RTStrDup(pszName);
+    if (!pMixBuf->pszName)
+        return VERR_NO_MEMORY;
+
+    AUDMIXBUF_LOG(("%s: uHz=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool\n",
+                   pMixBuf->pszName,
+                   AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
+                   AUDMIXBUF_FMT_CHANNELS(pMixBuf->AudioFmt),
+                   AUDMIXBUF_FMT_BITS_PER_SAMPLE(pMixBuf->AudioFmt),
+                   RT_BOOL(AUDMIXBUF_FMT_SIGNED(pMixBuf->AudioFmt))));
+
+    return audioMixBufAlloc(pMixBuf, cSamples);
+}
+
+/**
+ * Returns @true if there are any audio samples available for processing,
+ * @false if not.
+ *
+ * @return  bool                    @true if there are any audio samples available for processing, @false if not.
+ * @param   pMixBuf                 Mixing buffer to return value for.
+ */
+bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, true);
+
+    if (pMixBuf->pParent)
+        return (pMixBuf->cMixed == 0);
+    return (pMixBuf->cProcessed == 0);
+}
+
+/**
+ * Links an audio mixing buffer to a parent mixing buffer. A parent mixing
+ * buffer can have multiple children mixing buffers [1:N], whereas a child only can
+ * have one parent mixing buffer [N:1].
+ *
+ * The mixing direction always goes from the child/children buffer(s) to the
+ * parent buffer.
+ *
+ * For guest audio output the host backend owns the parent mixing buffer, the
+ * device emulation owns the child/children.
+ *
+ * The audio format of each mixing buffer can vary; the internal mixing code
+ * then will autiomatically do the (needed) conversion.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to link parent to.
+ * @param   pParent                 Parent mixing buffer to use for linking.
+ *
+ * @remark  Circular linking is not allowed.
+ */
+int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(pParent, VERR_INVALID_POINTER);
+
+    AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt),
+                    ("Parent sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
+    AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
+                    ("Buffer sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
+    AssertMsgReturn(pMixBuf != pParent,
+                    ("Circular linking not allowed\n"), VERR_INVALID_PARAMETER);
+
+    if (pMixBuf->pParent) /* Already linked? */
+    {
+        AUDMIXBUF_LOG(("%s: Already linked to \"%s\"\n",
+                       pMixBuf->pszName, pMixBuf->pParent->pszName));
+        return VERR_ACCESS_DENIED;
+    }
+
+    RTListAppend(&pParent->lstBuffers, &pMixBuf->Node);
+    pMixBuf->pParent = pParent;
+
+    /* Calculate the frequency ratio. */
+    pMixBuf->iFreqRatio = ((int64_t)AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt) << 32)
+                        /           AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt);
+
+    if (pMixBuf->iFreqRatio == 0) /* Catch division by zero. */
+        pMixBuf->iFreqRatio = 1 << 20; /* Do a 1:1 conversion instead. */
+
+    uint32_t cSamples = (uint32_t)RT_MIN(  ((uint64_t)pParent->cSamples << 32)
+                                         / pMixBuf->iFreqRatio, _64K /* 64K samples max. */);
+    if (!cSamples)
+        cSamples = pParent->cSamples;
+
+    int rc = VINF_SUCCESS;
+
+    if (cSamples != pMixBuf->cSamples)
+    {
+        AUDMIXBUF_LOG(("%s: Reallocating samples %RU32 -> %RU32\n",
+                       pMixBuf->pszName, pMixBuf->cSamples, cSamples));
+
+        uint32_t cbSamples = cSamples * sizeof(PDMAUDIOSAMPLE);
+        Assert(cbSamples);
+        pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemRealloc(pMixBuf->pSamples, cbSamples);
+        if (!pMixBuf->pSamples)
+            rc = VERR_NO_MEMORY;
+
+        if (RT_SUCCESS(rc))
+        {
+            pMixBuf->cSamples = cSamples;
+
+            /* Make sure to zero the reallocated buffer so that it can be
+             * used properly when blending with another buffer later. */
+            RT_BZERO(pMixBuf->pSamples, cbSamples);
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (!pMixBuf->pRate)
+        {
+            /* Create rate conversion. */
+            pMixBuf->pRate = (PPDMAUDIOSTRMRATE)RTMemAllocZ(sizeof(PDMAUDIOSTRMRATE));
+            if (!pMixBuf->pRate)
+                return VERR_NO_MEMORY;
+        }
+        else
+            RT_BZERO(pMixBuf->pRate, sizeof(PDMAUDIOSTRMRATE));
+
+        pMixBuf->pRate->dstInc = ((uint64_t)AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt) << 32)
+                               /            AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt);
+
+        AUDMIXBUF_LOG(("uThisHz=%RU32, uParentHz=%RU32, iFreqRatio=0x%RX64 (%RI64), uRateInc=0x%RX64 (%RU64), cSamples=%RU32 (%RU32 parent)\n",
+                       AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
+                       AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt),
+                       pMixBuf->iFreqRatio, pMixBuf->iFreqRatio,
+                       pMixBuf->pRate->dstInc, pMixBuf->pRate->dstInc,
+                       pMixBuf->cSamples,
+                       pParent->cSamples));
+        AUDMIXBUF_LOG(("%s (%RU32Hz) -> %s (%RU32Hz)\n",
+                       pMixBuf->pszName, AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
+                       pMixBuf->pParent->pszName, AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt)));
+    }
+
+    return rc;
+}
+
+/**
+ * Returns the number of audio samples mixed (processed) by
+ * the parent mixing buffer.
+ *
+ * @return  uint32_t                Number of audio samples mixed (processed).
+ * @param   pMixBuf                 Mixing buffer to return number from.
+ */
+uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, 0);
+
+    AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
+                              ("Buffer is not linked to a parent buffer\n"),
+                              0);
+
+    AUDMIXBUF_LOG(("%s: cMixed=%RU32\n", pMixBuf->pszName, pMixBuf->cMixed));
+    return pMixBuf->cMixed;
+}
+
+/**
+ * Mixes audio samples from a source mixing buffer to a destination mixing buffer.
+ *
+ * @return  IPRT status code.
+ * @param   pDst                    Destination mixing buffer.
+ * @param   pSrc                    Source mixing buffer.
+ * @param   cSamples                Number of source audio samples to mix.
+ * @param   pcProcessed             Number of audio samples successfully mixed.
+ */
+static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSamples, uint32_t *pcProcessed)
+{
+    AssertPtrReturn(pDst, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
+    AssertReturn(cSamples, VERR_INVALID_PARAMETER);
+    /* pcProcessed is optional. */
+
+    /* Live samples indicate how many samples there are in the source buffer
+     * which have not been processed yet by the destination buffer. */
+    uint32_t cLive = pSrc->cMixed;
+    if (cLive >= pDst->cSamples)
+        AUDMIXBUF_LOG(("Destination buffer \"%s\" full (%RU32 samples max), live samples = %RU32\n",
+                       pDst->pszName, pDst->cSamples, cLive));
+
+    /* Dead samples are the number of samples in the destination buffer which
+     * will not be needed, that is, are not needed in order to process the live
+     * samples of the source buffer. */
+    uint32_t cDead = pDst->cSamples - cLive;
+
+    uint32_t cToReadTotal = (uint32_t)RT_MIN(cSamples, AUDIOMIXBUF_S2S_RATIO(pSrc, cDead));
+    uint32_t offRead = 0;
+
+    uint32_t cReadTotal = 0;
+    uint32_t cWrittenTotal = 0;
+    uint32_t offWrite = (pDst->offReadWrite + cLive) % pDst->cSamples;
+
+    AUDMIXBUF_LOG(("pSrc=%s (%RU32 samples), pDst=%s (%RU32 samples), cLive=%RU32, cDead=%RU32, cToReadTotal=%RU32, offWrite=%RU32\n",
+                   pSrc->pszName, pSrc->cSamples, pDst->pszName, pDst->cSamples, cLive, cDead, cToReadTotal, offWrite));
+
+    uint32_t cToRead, cToWrite;
+    uint32_t cWritten, cRead;
+
+    while (cToReadTotal)
+    {
+        cDead = pDst->cSamples - cLive;
+
+        cToRead  = cToReadTotal;
+        cToWrite = RT_MIN(cDead, pDst->cSamples - offWrite);
+        if (!cToWrite)
+        {
+            AUDMIXBUF_LOG(("Warning: Destination buffer \"%s\" full\n", pDst->pszName));
+            break;
+        }
+
+        Assert(offWrite + cToWrite <= pDst->cSamples);
+        Assert(offRead + cToRead <= pSrc->cSamples);
+
+        AUDMIXBUF_LOG(("\t%RU32Hz -> %RU32Hz\n", AUDMIXBUF_FMT_SAMPLE_FREQ(pSrc->AudioFmt), AUDMIXBUF_FMT_SAMPLE_FREQ(pDst->AudioFmt)));
+        AUDMIXBUF_LOG(("\tcDead=%RU32, offWrite=%RU32, cToWrite=%RU32, offRead=%RU32, cToRead=%RU32\n",
+                       cDead, offWrite, cToWrite, offRead, cToRead));
+
+        audioMixBufOpBlend(pDst->pSamples + offWrite, cToWrite,
+                           pSrc->pSamples + offRead, cToRead,
+                           pSrc->pRate, &cWritten, &cRead);
+
+        AUDMIXBUF_LOG(("\t\tcWritten=%RU32, cRead=%RU32\n", cWritten, cRead));
+
+        cReadTotal    += cRead;
+        cWrittenTotal += cWritten;
+
+        offRead += cRead;
+        Assert(cToReadTotal >= cRead);
+        cToReadTotal -= cRead;
+
+        offWrite = (offWrite + cWritten) % pDst->cSamples;
+
+        cLive += cWritten;
+    }
+
+    pSrc->cMixed     += cWrittenTotal;
+    pDst->cProcessed += cWrittenTotal;
+#ifdef DEBUG
+    s_cSamplesMixedTotal += cWrittenTotal;
+    audioMixBufPrint(pDst);
+#endif
+
+    if (pcProcessed)
+        *pcProcessed = cReadTotal;
+
+    AUDMIXBUF_LOG(("cReadTotal=%RU32 (pcProcessed), cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstProc=%RU32\n",
+                   cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cProcessed));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Mixes (multiplexes) audio samples to all connected mixing buffer children.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to use.
+ * @param   cSamples                Number of audio samples to mix to children.
+ * @param   pcProcessed             Maximum number of audio samples successfully mixed
+ *                                  to all children. Optional.
+ */
+int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
+                             uint32_t *pcProcessed)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+
+    if (!cSamples)
+    {
+        if (pcProcessed)
+            *pcProcessed = 0;
+        return VINF_SUCCESS;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    uint32_t cProcessed;
+    uint32_t cProcessedMax = 0;
+
+    PPDMAUDIOMIXBUF pIter;
+    RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
+    {
+        rc = audioMixBufMixTo(pIter, pMixBuf, cSamples, &cProcessed);
+        if (RT_FAILURE(rc))
+            break;
+
+        cProcessedMax = RT_MAX(cProcessedMax, cProcessed);
+    }
+
+    if (pcProcessed)
+        *pcProcessed = cProcessedMax;
+
+    return rc;
+}
+
+/**
+ * Mixes audio samples down to the parent mixing buffer.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to mix samples down to parent.
+ * @param   cSamples                Number of audio samples to mix down.
+ * @param   pcProcessed             Number of audio samples successfully processed. Optional.
+ */
+int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
+                           uint32_t *pcProcessed)
+{
+    AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
+                    ("Buffer is not linked to a parent buffer\n"),
+                    VERR_INVALID_PARAMETER);
+
+    return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, cSamples, pcProcessed);
+}
+
+#ifdef DEBUG
+/**
+ * Prints statistics and status of a mixing buffer to the logger.
+ * For debug versions only.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to print.
+ */
+static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf)
+{
+    PPDMAUDIOMIXBUF pParent = pMixBuf;
+    if (pMixBuf->pParent)
+        pParent = pMixBuf->pParent;
+
+    AUDMIXBUF_LOG(("********************************************\n"));
+    AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
+                   pParent->pszName,
+                   pParent->offReadWrite, pParent->cProcessed, pParent->cMixed,
+                   AUDIOMIXBUF_S2B(pParent, 1)));
+
+    PPDMAUDIOMIXBUF pIter;
+    RTListForEach(&pParent->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
+    {
+        AUDMIXBUF_LOG(("\t%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
+                       pIter->pszName,
+                       pIter->offReadWrite, pIter->cProcessed, pIter->cMixed,
+                       AUDIOMIXBUF_S2B(pIter, 1)));
+    }
+    AUDMIXBUF_LOG(("Total samples mixed: %RU64\n", s_cSamplesMixedTotal));
+    AUDMIXBUF_LOG(("********************************************\n"));
+}
+#endif
+
+/**
+ * Returns the total number of samples processed.
+ *
+ * @return  uint32_t
+ * @param   pMixBuf
+ */
+uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, 0);
+
+    AUDMIXBUF_LOG(("%s: cProcessed=%RU32\n", pMixBuf->pszName, pMixBuf->cProcessed));
+    return pMixBuf->cProcessed;
+}
+
+/**
+ * Reads audio samples at a specific offset.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to read audio samples from.
+ * @param   offSamples              Offset (in audio samples) to start reading from.
+ * @param   pvBuf                   Pointer to buffer to write output to.
+ * @param   cbBuf                   Size (in bytes) of buffer to write to.
+ * @param   pcbRead                 Size (in bytes) of data read. Optional.
+ */
+int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf,
+                      uint32_t offSamples,
+                      void *pvBuf, uint32_t cbBuf,
+                      uint32_t *pcbRead)
+{
+    return AudioMixBufReadAtEx(pMixBuf, pMixBuf->AudioFmt,
+                               offSamples, pvBuf, cbBuf, pcbRead);
+}
+
+/**
+ * Reads audio samples at a specific offset.
+ * If the audio format of the mixing buffer and the requested audio format do
+ * not match the output will be converted accordingly.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to read audio samples from.
+ * @param   enmFmt                  Audio format to use for output.
+ * @param   offSamples              Offset (in audio samples) to start reading from.
+ * @param   pvBuf                   Pointer to buffer to write output to.
+ * @param   cbBuf                   Size (in bytes) of buffer to write to.
+ * @param   pcbRead                 Size (in bytes) of data read. Optional.
+ */
+int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
+                        uint32_t offSamples,
+                        void *pvBuf, uint32_t cbBuf,
+                        uint32_t *pcbRead)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    /* pcbRead is optional. */
+
+    uint32_t cDstSamples = pMixBuf->cSamples;
+    uint32_t cLive = pMixBuf->cProcessed;
+
+    uint32_t cDead = cDstSamples - cLive;
+    uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_S2S_RATIO(pMixBuf, cDead);
+    cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2S(pMixBuf, cbBuf));
+
+    AUDMIXBUF_LOG(("%s: offSamples=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
+                   pMixBuf->pszName, offSamples, cLive, cDead, cToProcess));
+
+    int rc;
+    if (cToProcess)
+    {
+        PAUDMIXBUF_FN_CONVTO pConv = audioMixBufConvToLookup(enmFmt);
+        if (pConv)
+        {
+            AUDMIXBUF_CONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
+            pConv(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
+
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+
+#ifdef DEBUG
+        audioMixBufPrint(pMixBuf);
+#endif
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcbRead)
+            *pcbRead = AUDIOMIXBUF_S2B(pMixBuf, cToProcess);
+    }
+
+    AUDMIXBUF_LOG(("cbRead=%RU32, rc=%Rrc\n", AUDIOMIXBUF_S2B(pMixBuf, cToProcess), rc));
+    return rc;
+}
+
+/**
+ * Reads audio samples. The audio format of the mixing buffer will be used.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to read audio samples from.
+ * @param   pvBuf                   Pointer to buffer to write output to.
+ * @param   cbBuf                   Size (in bytes) of buffer to write to.
+ * @param   pcRead                  Number of audio samples read. Optional.
+ */
+int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf,
+                        void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
+{
+    return AudioMixBufReadCircEx(pMixBuf, pMixBuf->AudioFmt,
+                                 pvBuf, cbBuf, pcRead);
+}
+
+/**
+ * Reads audio samples in a specific audio format.
+ * If the audio format of the mixing buffer and the requested audio format do
+ * not match the output will be converted accordingly.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to read audio samples from.
+ * @param   enmFmt                  Audio format to use for output.
+ * @param   pvBuf                   Pointer to buffer to write output to.
+ * @param   cbBuf                   Size (in bytes) of buffer to write to.
+ * @param   pcRead                  Number of audio samples read. Optional.
+ */
+int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
+                          void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    /* pcbRead is optional. */
+
+    if (!cbBuf)
+        return VINF_SUCCESS;
+
+    uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cProcessed);
+
+    AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
+                   pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
+
+    if (!cToRead)
+    {
+#ifdef DEBUG
+        audioMixBufPrint(pMixBuf);
+#endif
+        if (pcRead)
+            *pcRead = 0;
+        return VINF_SUCCESS;
+    }
+
+    PAUDMIXBUF_FN_CONVTO pConv = audioMixBufConvToLookup(enmFmt);
+    if (!pConv) /* Audio format not supported. */
+        return VERR_NOT_SUPPORTED;
+
+    PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
+    uint32_t cLenSrc1 = cToRead;
+
+    PPDMAUDIOSAMPLE pSamplesSrc2 = NULL;
+    uint32_t cLenSrc2 = 0;
+
+    uint32_t offRead = pMixBuf->offReadWrite + cToRead;
+
+    /*
+     * Do we need to wrap around to read all requested data, that is,
+     * starting at the beginning of our circular buffer? This then will
+     * be the optional second part to do.
+     */
+    if (offRead >= pMixBuf->cSamples)
+    {
+        Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
+        cLenSrc1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
+
+        pSamplesSrc2 = pMixBuf->pSamples;
+        Assert(cToRead >= cLenSrc1);
+        cLenSrc2 = RT_MIN(cToRead - cLenSrc1, pMixBuf->cSamples);
+
+        /* Save new read offset. */
+        offRead = cLenSrc2;
+    }
+
+    AUDMIXBUF_CONVOPTS convOpts;
+    convOpts.Volume = pMixBuf->Volume;
+
+    /* Anything to do at all? */
+    int rc = VINF_SUCCESS;
+    if (cLenSrc1)
+    {
+        convOpts.cSamples = cLenSrc1;
+
+        AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offReadWrite, cLenSrc1));
+        pConv(pvBuf, pSamplesSrc1, &convOpts);
+    }
+
+    /* Second part present? */
+    if (   RT_LIKELY(RT_SUCCESS(rc))
+        && cLenSrc2)
+    {
+        AssertPtr(pSamplesSrc2);
+
+        convOpts.cSamples = cLenSrc2;
+
+        AUDMIXBUF_LOG(("P2: cToRead=%RU32, offWrite=%RU32 (%zu bytes)\n", cLenSrc2, cLenSrc1,
+                       AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1)));
+        pConv((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+#ifdef DEBUG_DUMP_PCM_DATA
+        RTFILE fh;
+        rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
+                        RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        if (RT_SUCCESS(rc))
+        {
+            RTFileWrite(fh, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1 + cLenSrc2), NULL);
+            RTFileClose(fh);
+        }
+#endif
+        pMixBuf->offReadWrite  = offRead % pMixBuf->cSamples;
+        pMixBuf->cProcessed   -= RT_MIN(cLenSrc1 + cLenSrc2, pMixBuf->cProcessed);
+
+        if (pcRead)
+            *pcRead = cLenSrc1 + cLenSrc2;
+    }
+
+#ifdef DEBUG
+    audioMixBufPrint(pMixBuf);
+#endif
+
+    AUDMIXBUF_LOG(("cRead=%RU32 (%zu bytes), rc=%Rrc\n",
+                   cLenSrc1 + cLenSrc2,
+                   AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1 + cLenSrc2), rc));
+    return rc;
+}
+
+/**
+ * Resets a mixing buffer.
+ *
+ * @param   pMixBuf                 Mixing buffer to reset.
+ */
+void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturnVoid(pMixBuf);
+
+    AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
+
+    pMixBuf->offReadWrite = 0;
+    pMixBuf->cMixed       = 0;
+    pMixBuf->cProcessed   = 0;
+
+    AudioMixBufClear(pMixBuf);
+}
+
+/**
+ * Sets the overall (master) volume.
+ *
+ * @param   pMixBuf                 Mixing buffer to set volume for.
+ * @param   pVol                    Pointer to volume structure to set.
+ */
+void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol)
+{
+    AssertPtrReturnVoid(pMixBuf);
+    AssertPtrReturnVoid(pVol);
+
+    LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight));
+
+    pMixBuf->Volume.fMuted = pVol->fMuted;
+    /** @todo Ensure that the input is in the correct range/initialized! */
+    pMixBuf->Volume.uLeft  = s_aVolumeConv[pVol->uLeft  & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
+    pMixBuf->Volume.uRight = s_aVolumeConv[pVol->uRight & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
+
+    LogFlowFunc(("\t-> lVol=%#RX32, rVol=%#RX32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
+}
+
+/**
+ * Returns the maximum amount of audio samples this buffer can hold.
+ *
+ * @return  uint32_t                Size (in audio samples) the mixing buffer can hold.
+ * @param   pMixBuf                 Mixing buffer to retrieve maximum for.
+ */
+uint32_t AudioMixBufSize(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, 0);
+    return pMixBuf->cSamples;
+}
+
+/**
+ * Returns the maximum amount of bytes this buffer can hold.
+ *
+ * @return  uint32_t                Size (in bytes) the mixing buffer can hold.
+ * @param   pMixBuf                 Mixing buffer to retrieve maximum for.
+ */
+uint32_t AudioMixBufSizeBytes(PPDMAUDIOMIXBUF pMixBuf)
+{
+    AssertPtrReturn(pMixBuf, 0);
+    return AUDIOMIXBUF_S2B(pMixBuf, pMixBuf->cSamples);
+}
+
+/**
+ * Unlinks a mixing buffer from its parent, if any.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to unlink from parent.
+ */
+void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf)
+{
+    if (!pMixBuf || !pMixBuf->pszName)
+        return;
+
+    AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
+
+    if (pMixBuf->pParent)
+    {
+        AUDMIXBUF_LOG(("%s: Unlinking from parent \"%s\"\n",
+                       pMixBuf->pszName, pMixBuf->pParent->pszName));
+
+        RTListNodeRemove(&pMixBuf->Node);
+
+        /* Make sure to reset the parent mixing buffer each time it gets linked
+         * to a new child. */
+        AudioMixBufReset(pMixBuf->pParent);
+        pMixBuf->pParent = NULL;
+    }
+
+    PPDMAUDIOMIXBUF pIter;
+    while (!RTListIsEmpty(&pMixBuf->lstBuffers))
+    {
+        pIter = RTListGetFirst(&pMixBuf->lstBuffers, PDMAUDIOMIXBUF, Node);
+
+        AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pIter->pszName));
+
+        AudioMixBufReset(pIter->pParent);
+        pIter->pParent = NULL;
+
+        RTListNodeRemove(&pIter->Node);
+    }
+
+    if (pMixBuf->pRate)
+    {
+        pMixBuf->pRate->dstOffset = pMixBuf->pRate->srcOffset = 0;
+        pMixBuf->pRate->dstInc = 0;
+    }
+
+    pMixBuf->iFreqRatio = 1; /* Prevent division by zero. */
+}
+
+/**
+ * Writes audio samples at a specific offset.
+ * The sample format being written must match the format of the mixing buffer.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Pointer to mixing buffer to write to.
+ * @param   enmFmt                  Audio format supplied in the buffer.
+ * @param   offSamples              Offset (in samples) starting to write at.
+ * @param   pvBuf                   Pointer to audio buffer to be written.
+ * @param   cbBuf                   Size (in bytes) of audio buffer.
+ * @param   pcWritten               Returns number of audio samples written. Optional.
+ */
+int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf,
+                       uint32_t offSamples,
+                       const void *pvBuf, uint32_t cbBuf,
+                       uint32_t *pcWritten)
+{
+    return AudioMixBufWriteAtEx(pMixBuf, pMixBuf->AudioFmt,
+                                offSamples, pvBuf, cbBuf, pcWritten);
+}
+
+/**
+ * Writes audio samples at a specific offset. The audio sample format
+ * to be written can be different from the audio format the mixing buffer
+ * operates on.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Pointer to mixing buffer to write to.
+ * @param   enmFmt                  Audio format supplied in the buffer.
+ * @param   offSamples              Offset (in samples) starting to write at.
+ * @param   pvBuf                   Pointer to audio buffer to be written.
+ * @param   cbBuf                   Size (in bytes) of audio buffer.
+ * @param   pcWritten               Returns number of audio samples written. Optional.
+ */
+int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
+                         uint32_t offSamples,
+                         const void *pvBuf, uint32_t cbBuf,
+                         uint32_t *pcWritten)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    /* pcWritten is optional. */
+
+    uint32_t cDstSamples = pMixBuf->pParent
+                         ? pMixBuf->pParent->cSamples : pMixBuf->cSamples;
+    uint32_t cLive = pMixBuf->cProcessed;
+
+    uint32_t cDead = cDstSamples - cLive;
+    uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_S2S_RATIO(pMixBuf, cDead);
+    cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2S(pMixBuf, cbBuf));
+
+    AUDMIXBUF_LOG(("%s: offSamples=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
+                   pMixBuf->pszName, offSamples, cLive, cDead, cToProcess));
+
+    if (offSamples + cToProcess > pMixBuf->cSamples)
+        return VERR_BUFFER_OVERFLOW;
+
+    PAUDMIXBUF_FN_CONVFROM pConv = audioMixBufConvFromLookup(enmFmt, pMixBuf->Volume.fMuted);
+    if (!pConv)
+        return VERR_NOT_SUPPORTED;
+
+    int rc;
+    uint32_t cWritten;
+
+#ifdef DEBUG_DUMP_PCM_DATA
+    RTFILE fh;
+    rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
+                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+    if (RT_SUCCESS(rc))
+    {
+        RTFileWrite(fh, pvBuf, cbBuf, NULL);
+        RTFileClose(fh);
+    }
+#endif
+
+    if (cToProcess)
+    {
+        AUDMIXBUF_CONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
+
+        cWritten = pConv(pMixBuf->pSamples + offSamples, pvBuf, cbBuf, &convOpts);
+#ifdef DEBUG
+        audioMixBufPrint(pMixBuf);
+#endif
+        rc = cWritten ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Fudge! */
+    }
+    else
+    {
+        cWritten = 0;
+        rc = VINF_SUCCESS;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcWritten)
+            *pcWritten = cWritten;
+    }
+
+    AUDMIXBUF_LOG(("cWritten=%RU32, rc=%Rrc\n", cWritten, rc));
+    return rc;
+}
+
+/**
+ * Writes audio samples. The sample format being written must match the
+ * format of the mixing buffer.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Pointer to mixing buffer to write to.
+ * @param   pvBuf                   Pointer to audio buffer to be written.
+ * @param   cbBuf                   Size (in bytes) of audio buffer.
+ * @param   pcWritten               Returns number of audio samples written. Optional.
+ */
+int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf,
+                         const void *pvBuf, uint32_t cbBuf,
+                         uint32_t *pcWritten)
+{
+    return AudioMixBufWriteCircEx(pMixBuf, pMixBuf->AudioFmt, pvBuf, cbBuf, pcWritten);
+}
+
+/**
+ * Writes audio samples of a specific format.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Pointer to mixing buffer to write to.
+ * @param   enmFmt                  Audio format supplied in the buffer.
+ * @param   pvBuf                   Pointer to audio buffer to be written.
+ * @param   cbBuf                   Size (in bytes) of audio buffer.
+ * @param   pcWritten               Returns number of audio samples written. Optional.
+ */
+int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
+                           const void *pvBuf, uint32_t cbBuf,
+                           uint32_t *pcWritten)
+{
+    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    /* pcbWritten is optional. */
+
+    if (!cbBuf)
+    {
+        if (pcWritten)
+            *pcWritten = 0;
+        return VINF_SUCCESS;
+    }
+
+    PPDMAUDIOMIXBUF pParent = pMixBuf->pParent;
+
+    AUDMIXBUF_LOG(("%s: enmFmt=%ld, pBuf=%p, cbBuf=%zu, pParent=%p (%RU32)\n",
+                   pMixBuf->pszName, enmFmt, pvBuf, cbBuf, pParent, pParent ? pParent->cSamples : 0));
+
+    if (   pParent
+        && pParent->cSamples <= pMixBuf->cMixed)
+    {
+        if (pcWritten)
+            *pcWritten = 0;
+
+        AUDMIXBUF_LOG(("%s: Parent buffer %s is full\n",
+                       pMixBuf->pszName, pMixBuf->pParent->pszName));
+
+        return VINF_SUCCESS;
+    }
+
+    PAUDMIXBUF_FN_CONVFROM pConv = audioMixBufConvFromLookup(enmFmt, pMixBuf->Volume.fMuted);
+    if (!pConv)
+        return VERR_NOT_SUPPORTED;
+
+    int rc = VINF_SUCCESS;
+
+    uint32_t cToWrite = AUDIOMIXBUF_B2S(pMixBuf, cbBuf);
+    AssertMsg(cToWrite, ("cToWrite is 0 (cbBuf=%zu)\n", cbBuf));
+
+    PPDMAUDIOSAMPLE pSamplesDst1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
+    uint32_t cLenDst1 = cToWrite;
+
+    PPDMAUDIOSAMPLE pSamplesDst2 = NULL;
+    uint32_t cLenDst2 = 0;
+
+    uint32_t offWrite = pMixBuf->offReadWrite + cToWrite;
+
+    /*
+     * Do we need to wrap around to write all requested data, that is,
+     * starting at the beginning of our circular buffer? This then will
+     * be the optional second part to do.
+     */
+    if (offWrite >= pMixBuf->cSamples)
+    {
+        Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
+        cLenDst1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
+
+        pSamplesDst2 = pMixBuf->pSamples;
+        Assert(cToWrite >= cLenDst1);
+        cLenDst2 = RT_MIN(cToWrite - cLenDst1, pMixBuf->cSamples);
+
+        /* Save new read offset. */
+        offWrite = cLenDst2;
+    }
+
+    uint32_t cWrittenTotal = 0;
+
+    AUDMIXBUF_CONVOPTS convOpts;
+    convOpts.Volume = pMixBuf->Volume;
+
+    /* Anything to do at all? */
+    if (cLenDst1)
+    {
+        convOpts.cSamples = cLenDst1;
+        cWrittenTotal = pConv(pSamplesDst1, pvBuf, cbBuf, &convOpts);
+    }
+
+    /* Second part present? */
+    if (   RT_LIKELY(RT_SUCCESS(rc))
+        && cLenDst2)
+    {
+        AssertPtr(pSamplesDst2);
+
+        convOpts.cSamples = cLenDst2;
+        cWrittenTotal += pConv(pSamplesDst2, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), cbBuf, &convOpts);
+    }
+
+#ifdef DEBUG_DUMP_PCM_DATA
+        RTFILE fh;
+        RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeex.pcm",
+                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        RTFileWrite(fh, pSamplesDst1, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
+        RTFileClose(fh);
+#endif
+
+    AUDMIXBUF_LOG(("cLenDst1=%RU32, cLenDst2=%RU32, offWrite=%RU32\n",
+                   cLenDst1, cLenDst2, offWrite));
+
+    if (RT_SUCCESS(rc))
+    {
+        pMixBuf->offReadWrite = offWrite % pMixBuf->cSamples;
+        pMixBuf->cProcessed = RT_MIN(pMixBuf->cProcessed + cLenDst1 + cLenDst2,
+                                     pMixBuf->cSamples /* Max */);
+        if (pcWritten)
+            *pcWritten = cLenDst1 + cLenDst2;
+    }
+
+#ifdef DEBUG
+    audioMixBufPrint(pMixBuf);
+#endif
+
+    AUDMIXBUF_LOG(("cWritten=%RU32 (%zu bytes), rc=%Rrc\n",
+                   cLenDst1 + cLenDst2,
+                   AUDIOMIXBUF_S2B(pMixBuf, cLenDst1 + cLenDst2), rc));
+    return rc;
+}
+
diff --git a/src/VBox/Devices/Audio_50/AudioMixBuffer.h b/src/VBox/Devices/Audio_50/AudioMixBuffer.h
new file mode 100644
index 0000000..11c5912
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/AudioMixBuffer.h
@@ -0,0 +1,82 @@
+/* $Id: AudioMixBuffer.h $ */
+/** @file
+ * VBox audio: Mixing buffer to convert audio samples to/from different
+ *             rates / formats.
+ */
+
+/*
+ * Copyright (C) 2014-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef AUDIO_MIXBUF_H
+#define AUDIO_MIXBUF_H
+
+#include <iprt/cdefs.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+/** Constructs 32 bit value for given frequency, number of channels, bits per sample and signed bit.
+ *  Note: This currently matches 1:1 the VRDE encoding -- this might change in the future, so better don't rely on this fact! */
+#define AUDMIXBUF_AUDIO_FMT_MAKE(freq, c, bps, s) ((((s) & 0x1) << 28) + (((bps) & 0xFF) << 20) + (((c) & 0xF) << 16) + ((freq) & 0xFFFF))
+
+/** Decodes frequency (Hz). */
+#define AUDMIXBUF_FMT_SAMPLE_FREQ(a) ((a) & 0xFFFF)
+/** Decodes number of channels. */
+#define AUDMIXBUF_FMT_CHANNELS(a) (((a) >> 16) & 0xF)
+/** Decodes signed bit. */
+#define AUDMIXBUF_FMT_SIGNED(a) (((a) >> 28) & 0x1)
+/** Decodes number of bits per sample. */
+#define AUDMIXBUF_FMT_BITS_PER_SAMPLE(a) (((a) >> 20) & 0xFF)
+/** Decodes number of bytes per sample. */
+#define AUDMIXBUF_FMT_BYTES_PER_SAMPLE(a) ((AUDMIXBUF_AUDIO_FMT_BITS_PER_SAMPLE(a) + 7) / 8)
+
+/** Converts samples to bytes. */
+#define AUDIOMIXBUF_S2B(pBuf, samples) ((samples) << (pBuf)->cShift)
+/** Converts samples to bytes, respecting the conversion ratio to
+ *  a linked buffer. */
+#define AUDIOMIXBUF_S2B_RATIO(pBuf, samples) ((((int64_t) samples << 32) / (pBuf)->iFreqRatio) << (pBuf)->cShift)
+/** Converts bytes to samples, *not* taking the conversion ratio
+ *  into account. */
+#define AUDIOMIXBUF_B2S(pBuf, cb)  (cb >> (pBuf)->cShift)
+/** Converts number of samples according to the buffer's ratio. */
+#define AUDIOMIXBUF_S2S_RATIO(pBuf, samples)  (((int64_t) samples << 32) / (pBuf)->iFreqRatio)
+
+
+int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead, PPDMAUDIOSAMPLE *ppvSamples, uint32_t *pcSamplesRead);
+uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf);
+inline uint32_t AudioMixBufBytesToSamples(PPDMAUDIOMIXBUF pMixBuf);
+void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf);
+void AudioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf);
+void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear);
+uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf);
+uint32_t AudioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf);
+int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMPCMPROPS pProps, uint32_t cSamples);
+bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf);
+int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent);
+uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf);
+int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
+int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
+uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf);
+int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
+int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
+int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
+int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
+void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf);
+void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol);
+uint32_t AudioMixBufSize(PPDMAUDIOMIXBUF pMixBuf);
+uint32_t AudioMixBufSizeBytes(PPDMAUDIOMIXBUF pMixBuf);
+void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf);
+int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
+int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
+int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
+int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
+
+#endif /* !AUDIO_MIXBUF_H */
+
diff --git a/src/VBox/Devices/Audio_50/AudioMixer.cpp b/src/VBox/Devices/Audio_50/AudioMixer.cpp
new file mode 100644
index 0000000..83a082f
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/AudioMixer.cpp
@@ -0,0 +1,520 @@
+/* $Id: AudioMixer.cpp $ */
+/** @file
+ * VBox audio: Mixing routines, mainly used by the various audio device
+ *             emulations to achieve proper multiplexing from/to attached
+ *             devices LUNs.
+ */
+
+/*
+ * Copyright (C) 2014-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#define LOG_GROUP LOG_GROUP_AUDIO_MIXER
+#include <VBox/log.h>
+#include "AudioMixer.h"
+#include "AudioMixBuffer.h"
+
+#include <VBox/vmm/pdm.h>
+#include <VBox/err.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+#include <iprt/alloc.h>
+#include <iprt/asm-math.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster);
+
+
+int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink)
+{
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    /** ppSink is optional. */
+
+    int rc = VINF_SUCCESS;
+
+    PAUDMIXSINK pSink = (PAUDMIXSINK)RTMemAllocZ(sizeof(AUDMIXSINK));
+    if (pSink)
+    {
+        pSink->pszName = RTStrDup(pszName);
+        if (!pSink->pszName)
+            rc = VERR_NO_MEMORY;
+
+        if (RT_SUCCESS(rc))
+        {
+            pSink->pParent  = pMixer;
+            pSink->cStreams = 0;
+            pSink->enmDir   = enmDir;
+            RTListInit(&pSink->lstStreams);
+
+            /* Set initial volume to max. */
+            pSink->Volume.fMuted = false;
+            pSink->Volume.uLeft  = 0x7F;
+            pSink->Volume.uRight = 0x7F;
+
+            RTListAppend(&pMixer->lstSinks, &pSink->Node);
+            pMixer->cSinks++;
+
+            LogFlowFunc(("pMixer=%p, pSink=%p, cSinks=%RU8\n",
+                         pMixer, pSink, pMixer->cSinks));
+
+            if (ppSink)
+                *ppSink = pSink;
+        }
+        else
+            RTMemFree(pSink);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream,
+                          uint32_t uFlags, PAUDMIXSTREAM *ppStream)
+{
+    RT_NOREF(uFlags);
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    /** @todo Add flag validation. */
+    /* ppStream is optional. */
+
+    int rc;
+
+    if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
+        return VERR_TOO_MUCH_DATA;
+
+    PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
+    if (pMixStream)
+    {
+        pMixStream->pConn = pConnector;
+        pMixStream->pIn   = pStream;
+        /** @todo Process flags. */
+
+        RTListAppend(&pSink->lstStreams, &pMixStream->Node);
+        pSink->cStreams++;
+
+        LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
+                     pSink->pszName, pMixStream, pSink->cStreams));
+
+        /* Increase the stream's reference count to let others know
+         * we're reyling on it to be around now. */
+        pStream->State.cRefs++;
+
+        if (ppStream)
+            *ppStream = pMixStream;
+
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream,
+                           uint32_t uFlags, PAUDMIXSTREAM *ppStream)
+{
+    RT_NOREF(uFlags);
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    /** @todo Add flag validation. */
+    /* ppStream is optional. */
+
+    int rc;
+
+    if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
+        return VERR_TOO_MUCH_DATA;
+
+    PAUDMIXSTREAM pMixStream
+        = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
+    if (pMixStream)
+    {
+        pMixStream->pConn = pConnector;
+        pMixStream->pOut  = pStream;
+        /** @todo Process flags. */
+
+        RTListAppend(&pSink->lstStreams, &pMixStream->Node);
+        pSink->cStreams++;
+
+        LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
+                     pSink->pszName, pMixStream, pSink->cStreams));
+
+        /* Increase the stream's reference count to let others know
+         * we're reyling on it to be around now. */
+        pStream->State.cRefs++;
+
+        if (ppStream)
+            *ppStream = pMixStream;
+
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+int AudioMixerControlStream(PAUDIOMIXER pMixer, PAUDMIXSTREAM pHandle)
+{
+    RT_NOREF(pMixer, pHandle);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer)
+{
+    RT_NOREF(uFlags);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    /** @todo Add flag validation. */
+    AssertPtrReturn(ppMixer, VERR_INVALID_POINTER);
+
+    int rc = VINF_SUCCESS;
+
+    PAUDIOMIXER pMixer = (PAUDIOMIXER)RTMemAllocZ(sizeof(AUDIOMIXER));
+    if (pMixer)
+    {
+        pMixer->pszName = RTStrDup(pszName);
+        if (!pMixer->pszName)
+            rc = VERR_NO_MEMORY;
+
+        if (RT_SUCCESS(rc))
+        {
+            pMixer->cSinks = 0;
+            RTListInit(&pMixer->lstSinks);
+
+            pMixer->VolMaster.fMuted = false;
+            pMixer->VolMaster.uLeft  = UINT32_MAX;
+            pMixer->VolMaster.uRight = UINT32_MAX;
+
+            LogFlowFunc(("Created %p ...\n", pMixer));
+
+            *ppMixer = pMixer;
+        }
+        else
+            RTMemFree(pMixer);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+void AudioMixerDestroy(PAUDIOMIXER pMixer)
+{
+    if (!pMixer)
+        return;
+
+    LogFlowFunc(("Destroying %s ...\n", pMixer->pszName));
+
+    PAUDMIXSINK pSink, pSinkNext;
+    RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node)
+        AudioMixerRemoveSink(pMixer, pSink);
+
+    Assert(pMixer->cSinks == 0);
+
+    if (pMixer->pszName)
+    {
+        RTStrFree(pMixer->pszName);
+        pMixer->pszName = NULL;
+    }
+
+    RTMemFree(pMixer);
+}
+
+static void audioMixerDestroySink(PAUDMIXSINK pSink)
+{
+    AssertPtrReturnVoid(pSink);
+    if (!pSink)
+        return;
+
+    if (pSink->pszName)
+        RTStrFree(pSink->pszName);
+
+    RTMemFree(pSink);
+}
+
+static void audioMixerDestroyStream(PAUDMIXSTREAM pStream)
+{
+    AssertPtrReturnVoid(pStream);
+    if (!pStream)
+        return;
+
+    RTMemFree(pStream);
+}
+
+int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    /** @todo Perform a deep copy, if needed. */
+    *pCfg = pMixer->devFmt;
+
+    return VINF_SUCCESS;
+}
+
+uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer)
+{
+    AssertPtrReturn(pMixer, 0);
+
+    uint32_t cStreams = 0;
+
+    PAUDMIXSINK pSink;
+    RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
+        cStreams += pSink->cStreams;
+
+    return cStreams;
+}
+
+void AudioMixerInvalidate(PAUDIOMIXER pMixer)
+{
+    AssertPtrReturnVoid(pMixer);
+
+    LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName));
+
+    /* Propagate new master volume to all connected sinks. */
+    PAUDMIXSINK pSink;
+    RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
+    {
+        int rc2 = audioMixerUpdateSinkVolume(pSink, &pMixer->VolMaster);
+        AssertRC(rc2);
+    }
+}
+
+int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
+{
+    RT_NOREF(enmOp);
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
+    /* pcbProcessed is optional. */
+
+    /** @todo Handle mixing operation enmOp! */
+
+    uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
+    if (!pvMixBuf)
+        return VERR_NO_MEMORY;
+
+    int rc = VERR_NOT_FOUND;
+    uint32_t cbProcessed = 0;
+
+    LogFlowFunc(("%s: pvBuf=%p, cbBuf=%zu\n", pSink->pszName, pvBuf, cbBuf));
+
+    PAUDMIXSTREAM pStream;
+    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
+    {
+        /** @todo Support output sinks as well! */
+        if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->pIn))
+            continue;
+
+        uint32_t cbTotalRead = 0;
+        uint32_t cbToRead = cbBuf;
+
+        while (cbToRead)
+        {
+            uint32_t cbRead;
+            AssertPtr(pStream->pConn);
+            rc = pStream->pConn->pfnRead(pStream->pConn, pStream->pIn,
+                                         (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbRead);
+            if (   RT_FAILURE(rc)
+                || !cbRead)
+                break;
+
+            AssertBreakStmt(cbRead <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
+            cbToRead -= cbRead;
+            cbTotalRead += cbRead;
+        }
+
+        if (RT_FAILURE(rc))
+            continue;
+
+        cbProcessed = RT_MAX(cbProcessed, cbTotalRead);
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        memcpy(pvBuf, pvMixBuf, cbProcessed); /* @todo Use an intermediate mixing buffer per sink! */
+
+        if (pcbProcessed)
+            *pcbProcessed = cbProcessed;
+    }
+
+    RTMemFree(pvMixBuf);
+
+    LogFlowFunc(("cbProcessed=%RU32, rc=%Rrc\n", cbProcessed, rc));
+    return rc;
+}
+
+int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
+{
+    RT_NOREF(pSink, enmOp, pvBuf, cbBuf, pcbProcessed);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
+{
+    AssertPtrReturnVoid(pMixer);
+    if (!pSink)
+        return;
+
+    PAUDMIXSTREAM pStream, pStreamNext;
+    RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
+        AudioMixerRemoveStream(pSink, pStream);
+
+    Assert(pSink->cStreams == 0);
+
+    RTListNodeRemove(&pSink->Node);
+    Assert(pMixer->cSinks);
+    pMixer->cSinks--;
+
+    LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n",
+                 pMixer->pszName, pSink->pszName, pMixer->cSinks));
+
+    audioMixerDestroySink(pSink);
+}
+
+void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
+{
+    AssertPtrReturnVoid(pSink);
+    if (!pStream)
+        return;
+
+    Assert(pSink->cStreams);
+    RTListNodeRemove(&pStream->Node);
+    pSink->cStreams--;
+
+#ifdef DEBUG
+    const char *pszStream = pSink->enmDir == AUDMIXSINKDIR_INPUT
+                          ? pStream->pIn->MixBuf.pszName : pStream->pOut->MixBuf.pszName;
+
+    LogFlowFunc(("%s: pStream=%s, cStreams=%RU8\n",
+                 pSink->pszName, pszStream ? pszStream : "<Unnamed>", pSink->cStreams));
+#endif
+
+    /* Decrease the reference count again. */
+    switch (pSink->enmDir)
+    {
+        case AUDMIXSINKDIR_INPUT:
+        {
+            Assert(pStream->pIn->State.cRefs);
+            pStream->pIn->State.cRefs--;
+            break;
+        }
+
+        case AUDMIXSINKDIR_OUTPUT:
+        {
+            Assert(pStream->pOut->State.cRefs);
+            pStream->pOut->State.cRefs--;
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Not implemented\n"));
+            break;
+    }
+
+    audioMixerDestroyStream(pStream);
+}
+
+int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    /** @todo Perform a deep copy, if needed. */
+    pMixer->devFmt = *pCfg;
+
+    return VINF_SUCCESS;
+}
+
+static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster)
+{
+    AssertPtrReturn(pSink,      VERR_INVALID_POINTER);
+    AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+                  pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
+    LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+                  pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
+
+    /** @todo Very crude implementation for now -- needs more work! */
+
+    PDMAUDIOVOLUME volSink;
+    volSink.fMuted  = pVolMaster->fMuted || pSink->Volume.fMuted;
+    volSink.uLeft   = (pSink->Volume.uLeft  * pVolMaster->uLeft)  / UINT8_MAX;
+    volSink.uRight  = (pSink->Volume.uRight * pVolMaster->uRight) / UINT8_MAX;
+
+    LogFlowFunc(("\t-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+                  volSink.fMuted, volSink.uLeft, volSink.uRight));
+
+    bool fOut = pSink->enmDir == AUDMIXSINKDIR_OUTPUT;
+
+    /* Propagate new sink volume to all streams in the sink. */
+    PAUDMIXSTREAM pStream;
+    RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
+    {
+        if (fOut)
+            AudioMixBufSetVolume(&pStream->pOut->MixBuf, &volSink);
+        else
+            AudioMixBufSetVolume(&pStream->pIn->MixBuf,  &volSink);
+    }
+
+    return VINF_SUCCESS;
+}
+
+/** Set the master volume of the mixer. */
+int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol)
+{
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+    AssertPtrReturn(pVol,   VERR_INVALID_POINTER);
+
+    pMixer->VolMaster = *pVol;
+
+    LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+                 pMixer->pszName, pVol->uLeft, pVol->uRight,
+                 pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
+
+    AudioMixerInvalidate(pMixer);
+    return VINF_SUCCESS;
+}
+
+/** Set the volume of an individual sink. */
+int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
+{
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pVol,  VERR_INVALID_POINTER);
+    AssertPtr(pSink->pParent);
+
+    LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
+
+    pSink->Volume = *pVol;
+
+    return audioMixerUpdateSinkVolume(pSink, &pSink->pParent->VolMaster);
+}
+
+void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+    RT_NOREF(pszArgs);
+    PAUDMIXSINK pSink;
+    unsigned    iSink = 0;
+
+    pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName,
+                    pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted);
+
+    RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
+    {
+        pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName,
+                        pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted);
+        ++iSink;
+    }
+}
diff --git a/src/VBox/Devices/Audio_50/AudioMixer.h b/src/VBox/Devices/Audio_50/AudioMixer.h
new file mode 100644
index 0000000..e22f475
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/AudioMixer.h
@@ -0,0 +1,113 @@
+/* $Id: AudioMixer.h $ */
+/** @file
+ * VBox audio: Mixing routines, mainly used by the various audio device
+ *             emulations to achieve proper multiplexing from/to attached
+ *             devices LUNs.
+ */
+
+/*
+ * Copyright (C) 2014-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef AUDIO_MIXER_H
+#define AUDIO_MIXER_H
+
+#include <iprt/cdefs.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+typedef struct AUDIOMIXER
+{
+    /** Mixer name. */
+    char                   *pszName;
+    /** Format the mixer should convert/output
+     *  data to so that the underlying device emulation
+     *  can work with it. */
+    PDMAUDIOSTREAMCFG       devFmt;
+    /** The master volume of this mixer. */
+    PDMAUDIOVOLUME          VolMaster;
+    /* List of audio mixer sinks. */
+    RTLISTANCHOR            lstSinks;
+    /** Number of used audio sinks. */
+    uint8_t                 cSinks;
+} AUDIOMIXER, *PAUDIOMIXER;
+
+typedef struct AUDMIXSTREAM
+{
+    RTLISTNODE              Node;
+    PPDMIAUDIOCONNECTOR     pConn;
+    union
+    {
+        PPDMAUDIOGSTSTRMIN  pIn;
+        PPDMAUDIOGSTSTRMOUT pOut;
+    };
+} AUDMIXSTREAM, *PAUDMIXSTREAM;
+
+typedef enum AUDMIXSINKDIR
+{
+    AUDMIXSINKDIR_UNKNOWN = 0,
+    AUDMIXSINKDIR_INPUT,
+    AUDMIXSINKDIR_OUTPUT,
+    /** The usual 32-bit hack. */
+    AUDMIXSINKDIR_32BIT_HACK = 0x7fffffff
+} AUDMIXSINKDIR;
+
+typedef struct AUDMIXSINK
+{
+    RTLISTNODE              Node;
+    /** Name of this sink. */
+    char                   *pszName;
+    /** The sink direction, that is,
+     *  if this sink handles input or output. */
+    AUDMIXSINKDIR           enmDir;
+    /** Pointer to mixer object this sink is bound
+     *  to. */
+    PAUDIOMIXER             pParent;
+    /** Number of streams assigned. */
+    uint8_t                 cStreams;
+    /** List of assigned streams. */
+    RTLISTANCHOR            lstStreams;
+    /** This sink's mixing buffer. */
+    PDMAUDIOMIXBUF          MixBuf;
+    /** The volume of this sink. The volume always will
+     *  be combined with the mixer's master volume. */
+    PDMAUDIOVOLUME          Volume;
+} AUDMIXSINK, *PAUDMIXSINK;
+
+typedef enum AUDMIXOP
+{
+    AUDMIXOP_NONE = 0,
+    AUDMIXOP_COPY,
+    AUDMIXOP_BLEND,
+    /** The usual 32-bit hack. */
+    AUDMIXOP_32BIT_HACK = 0x7fffffff
+} AUDMIXOP;
+
+
+int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink);
+int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream, uint32_t uFlags, PAUDMIXSTREAM *ppStream);
+int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream, uint32_t uFlags, PAUDMIXSTREAM *ppStream);
+int AudioMixerControlStream(AUDMIXSTREAM pHandle); /** @todo Implement me. */
+int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer);
+void AudioMixerDestroy(PAUDIOMIXER pMixer);
+int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
+uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer);
+void AudioMixerInvalidate(PAUDIOMIXER pMixer);
+int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed);
+int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed);
+void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink);
+void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
+int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
+int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol);
+int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
+void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs);
+
+#endif /* AUDIO_MIXER_H */
+
diff --git a/src/VBox/Devices/Audio/DevIchHda.cpp b/src/VBox/Devices/Audio_50/DevHDA.cpp
similarity index 60%
rename from src/VBox/Devices/Audio/DevIchHda.cpp
rename to src/VBox/Devices/Audio_50/DevHDA.cpp
index cf8d68b..acc0e34 100644
--- a/src/VBox/Devices/Audio/DevIchHda.cpp
+++ b/src/VBox/Devices/Audio_50/DevHDA.cpp
@@ -1,4 +1,4 @@
-/* $Id: DevIchHda.cpp $ */
+/* $Id: DevHDA.cpp $ */
 /** @file
  * DevIchHda - VBox ICH Intel HD Audio Controller.
  *
@@ -32,7 +32,6 @@
 #include <iprt/assert.h>
 #include <iprt/asm.h>
 #include <iprt/asm-math.h>
-#include <iprt/file.h>
 #include <iprt/list.h>
 #ifdef IN_RING3
 # include <iprt/mem.h>
@@ -46,7 +45,6 @@
 #include "AudioMixBuffer.h"
 #include "AudioMixer.h"
 #include "DevIchHdaCodec.h"
-#include "DevIchHdaCommon.h"
 #include "DrvAudio.h"
 
 
@@ -57,18 +55,6 @@
 #define VBOX_WITH_INTEL_HDA
 
 #ifdef DEBUG_andy
-/*
- * HDA_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust HDA_DEBUG_DUMP_PCM_DATA_PATH
- * to your needs before using this!
- */
-# define HDA_DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-#  define HDA_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-#  define HDA_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
-# endif
-
 /* Enables experimental support for separate mic-in handling.
    Do not enable this yet for regular builds, as this needs more testing first! */
 //# define VBOX_WITH_HDA_MIC_IN
@@ -98,39 +84,17 @@
  * writes 1, hw sets it to 1 (after completion), sw reads 1, sw writes 0). */
 #define BIRD_THINKS_CORBRP_IS_MOSTLY_RO
 
-/* Make sure that interleaving streams support is enabled if the 5.1 code is being used. */
-#if defined (VBOX_WITH_HDA_51_SURROUND) && !defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT)
-# define VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
-#endif
-
-/**
- * At the moment we support 4 input + 4 output streams max, which is 8 in total.
- * Bidirectional streams are currently *not* supported.
- *
- * Note: When changing any of those values, be prepared for some saved state
- *       fixups / trouble!
- */
-#define HDA_MAX_SDI             4
-#define HDA_MAX_SDO             4
-#define HDA_MAX_STREAMS         (HDA_MAX_SDI + HDA_MAX_SDO)
-AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
-
-/** Number of general registers. */
-#define HDA_NUM_GENERAL_REGS    34
-/** Number of total registers in the HDA's register map. */
-#define HDA_NUM_REGS            (HDA_NUM_GENERAL_REGS + (HDA_MAX_STREAMS * 10 /* Each stream descriptor has 10 registers */))
-/** Total number of stream tags (channels). Index 0 is reserved / invalid. */
-#define HDA_MAX_TAGS            16
+#define HDA_NREGS           114
+#define HDA_NREGS_SAVED     112
 
 /**
- * NB: Register values stored in memory (au32Regs[]) are indexed through
- * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
- * register descriptors in g_aHdaRegMap[] are indexed through the
- * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
+ *  NB: Register values stored in memory (au32Regs[]) are indexed through
+ *  the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
+ *  register descriptors in g_aHdaRegMap[] are indexed through the
+ *  HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
  *
- * The au32Regs[] layout is kept unchanged for saved state
- * compatibility.
- */
+ *  The au32Regs[] layout is kept unchanged for saved state
+ *  compatibility. */
 
 /* Registers */
 #define HDA_REG_IND_NAME(x)                 HDA_REG_##x
@@ -149,14 +113,14 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
  * oss (15:12) - number of output streams supported
  * iss (11:8)  - number of input streams supported
  * bss (7:3)   - number of bidirectional streams supported
- * bds (2:1)   - number of serial data out (SDO) signals supported
+ * bds (2:1)   - number of serial data out signals supported
  * b64sup (0)  - 64 bit addressing supported.
  */
 #define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \
-    (  (((oss)   & 0xF)  << 12) \
-     | (((iss)   & 0xF)  << 8)  \
-     | (((bss)   & 0x1F) << 3)  \
-     | (((bds)   & 0x3)  << 1)  \
+    (  (((oss) & 0xF)  << 12)   \
+     | (((iss) & 0xF)  << 8)    \
+     | (((bss) & 0x1F) << 3)    \
+     | (((bds) & 0x3)  << 2)    \
      | ((b64sup) & 1))
 
 #define HDA_REG_VMIN                1 /* 0x02 */
@@ -222,14 +186,14 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
 #define HDA_INTSTS_S7_SHIFT         7
 #define HDA_INTSTS_S_MASK(num)      RT_BIT(HDA_REG_FIELD_SHIFT(S##num))
 
-#define HDA_REG_WALCLK              13 /* 0x30 */
+#define HDA_REG_WALCLK              13 /* 0x24 */
 #define HDA_RMX_WALCLK              /* Not defined! */
 
 /* Note: The HDA specification defines a SSYNC register at offset 0x38. The
  * ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches
  * the datasheet.
  */
-#define HDA_REG_SSYNC               14 /* 0x38 */
+#define HDA_REG_SSYNC               14 /* 0x34 */
 #define HDA_RMX_SSYNC               12
 
 #define HDA_REG_CORBLBASE           15 /* 0x40 */
@@ -325,16 +289,14 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
 
 #define HDA_SD_NUM_FROM_REG(pThis, func, reg)   ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
 
-/** @todo Condense marcos! */
-
-#define HDA_REG_SD0CTL              HDA_NUM_GENERAL_REGS /* 0x80 */
-#define HDA_REG_SD1CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 10)  /* 0xA0 */
-#define HDA_REG_SD2CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 20)  /* 0xC0 */
-#define HDA_REG_SD3CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 30)  /* 0xE0 */
-#define HDA_REG_SD4CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 40)  /* 0x100 */
-#define HDA_REG_SD5CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 50)  /* 0x120 */
-#define HDA_REG_SD6CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 60)  /* 0x140 */
-#define HDA_REG_SD7CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 70)  /* 0x160 */
+#define HDA_REG_SD0CTL              34 /* 0x80 */
+#define HDA_REG_SD1CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 10) /* 0xA0 */
+#define HDA_REG_SD2CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 20) /* 0xC0 */
+#define HDA_REG_SD3CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 30) /* 0xE0 */
+#define HDA_REG_SD4CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 40) /* 0x100 */
+#define HDA_REG_SD5CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 50) /* 0x120 */
+#define HDA_REG_SD6CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 60) /* 0x140 */
+#define HDA_REG_SD7CTL              (HDA_STREAM_REG_DEF(CTL, 0) + 70) /* 0x160 */
 #define HDA_RMX_SD0CTL              32
 #define HDA_RMX_SD1CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
 #define HDA_RMX_SD2CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 20)
@@ -480,15 +442,15 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
  * formula: size - 1
  * Other values not listed are not supported.
  */
-#define HDA_SDIFIFO_120B            0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
-#define HDA_SDIFIFO_160B            0x9F /* 20-, 24-bit Input Streams Streams */
-
-#define HDA_SDOFIFO_16B             0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_32B             0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_64B             0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_128B            0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_192B            0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_256B            0xFF /* 20-, 24-bit Output Streams */
+#define HDA_SDINFIFO_120B           0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
+#define HDA_SDINFIFO_160B           0x9F /* 20-, 24-bit Input Streams Streams */
+
+#define HDA_SDONFIFO_16B            0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_32B            0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_64B            0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_128B           0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_192B           0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_256B           0xFF /* 20-, 24-bit Output Streams */
 #define SDFIFOS(pThis, num)         HDA_REG((pThis), SD(FIFOS, num))
 
 #define HDA_REG_SD0FMT              41 /* 0x92 */
@@ -508,10 +470,17 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
 #define HDA_RMX_SD6FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 60)
 #define HDA_RMX_SD7FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 70)
 
-#define SDFMT(pThis, num)               (HDA_REG((pThis), SD(FMT, num)))
-#define HDA_SDFMT_BASE_RATE(pThis, num) ((SDFMT(pThis, num)   & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE))
-#define HDA_SDFMT_MULT(pThis, num)      ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT))
-#define HDA_SDFMT_DIV(pThis, num)       ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV))
+#define SDFMT(pThis, num)           (HDA_REG((pThis), SD(FMT, num)))
+#define HDA_SDFMT_BASE_RATE_SHIFT   14
+#define HDA_SDFMT_MULT_SHIFT        11
+#define HDA_SDFMT_MULT_MASK         0x7
+#define HDA_SDFMT_DIV_SHIFT         8
+#define HDA_SDFMT_DIV_MASK          0x7
+#define HDA_SDFMT_BITS_SHIFT        4
+#define HDA_SDFMT_BITS_MASK         0x7
+#define SDFMT_BASE_RATE(pThis, num) ((SDFMT(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE))
+#define SDFMT_MULT(pThis, num)      ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT))
+#define SDFMT_DIV(pThis, num)       ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV))
 
 #define HDA_REG_SD0BDPL             42 /* 0x98 */
 #define HDA_REG_SD1BDPL             (HDA_STREAM_REG_DEF(BDPL, 0) + 10) /* 0xB8 */
@@ -570,7 +539,7 @@ typedef struct HDABDLESTATE
      *  Used to check if we need fill up the FIFO again. */
     uint32_t     cbBelowFIFOW;
     /** The buffer descriptor's internal DMA buffer. */
-    uint8_t      au8FIFO[HDA_SDOFIFO_256B + 1];
+    uint8_t      au8FIFO[HDA_SDONFIFO_256B + 1];
     /** Current offset in DMA buffer (in bytes).*/
     uint32_t     u32BufOff;
     uint32_t     Padding;
@@ -598,70 +567,30 @@ typedef struct HDABDLE
 } HDABDLE, *PHDABDLE;
 
 /**
- * Structure for keeping an audio stream data mapping.
- */
-typedef struct HDASTREAMMAPPING
-{
-    /** The stream's layout. */
-    PDMAUDIOSTREAMLAYOUT              enmLayout;
-    /** Number of audio channels in this stream. */
-    uint8_t                           cChannels;
-    /** Array audio channels. */
-    R3PTRTYPE(PPDMAUDIOSTREAMCHANNEL) paChannels;
-    R3PTRTYPE(PRTCIRCBUF)             pCircBuf;
-} HDASTREAMMAPPING, *PHDASTREAMMAPPING;
-
-/**
  * Internal state of a HDA stream.
  */
 typedef struct HDASTREAMSTATE
 {
     /** Current BDLE to use. Wraps around to 0 if
      *  maximum (cBDLE) is reached. */
-    uint16_t                uCurBDLE;
+    uint16_t            uCurBDLE;
     /** Stop indicator. */
-    volatile bool           fDoStop;
+    volatile bool       fDoStop;
     /** Flag indicating whether this stream is in an
      *  active (operative) state or not. */
-    volatile bool           fActive;
+    volatile bool       fActive;
     /** Flag indicating whether this stream currently is
      *  in reset mode and therefore not acccessible by the guest. */
-    volatile bool           fInReset;
+    volatile bool       fInReset;
     /** Unused, padding. */
-    bool                    fPadding;
-    /** Critical section to serialize access. */
-    RTCRITSECT              CritSect;
+    bool                fPadding;
     /** Event signalling that the stream's state has been changed. */
-    RTSEMEVENT              hStateChangedEvent;
-    /** This stream's data mapping. */
-    HDASTREAMMAPPING        Mapping;
+    RTSEMEVENT          hStateChangedEvent;
     /** Current BDLE (Buffer Descriptor List Entry). */
-    HDABDLE                 BDLE;
+    HDABDLE             BDLE;
 } HDASTREAMSTATE, *PHDASTREAMSTATE;
 
 /**
- * Structure defining an HDA mixer sink.
- * Its purpose is to know which audio mixer sink is bound to
- * which SDn (SDI/SDO) device stream.
- *
- * This is needed in order to handle interleaved streams
- * (that is, multiple channels in one stream) or non-interleaved
- * streams (each channel has a dedicated stream).
- *
- * This is only known to the actual device emulation level.
- */
-typedef struct HDAMIXERSINK
-{
-    /** SDn ID this sink is assigned to. 0 if not assigned. */
-    uint8_t                uSD;
-    /** Channel ID of SDn ID. Only valid if SDn ID is valid. */
-    uint8_t                uChannel;
-    uint8_t                Padding[3];
-    /** Pointer to the actual audio mixer sink. */
-    R3PTRTYPE(PAUDMIXSINK) pMixSink;
-} HDAMIXERSINK, *PHDAMIXERSINK;
-
-/**
  * Structure for keeping a HDA stream state.
  *
  * Contains only register values which do *not* change until a
@@ -669,60 +598,44 @@ typedef struct HDAMIXERSINK
  */
 typedef struct HDASTREAM
 {
-    /** Stream descriptor number (SDn). */
-    uint8_t                  u8SD;
-    uint8_t                  Padding0[7];
+    /** Stream number (SDn). */
+    uint8_t        u8Strm;
+    uint8_t        Padding0[7];
     /** DMA base address (SDnBDPU - SDnBDPL). */
-    uint64_t                 u64BDLBase;
+    uint64_t       u64BDLBase;
     /** Cyclic Buffer Length (SDnCBL).
      *  Represents the size of the ring buffer. */
-    uint32_t                 u32CBL;
+    uint32_t       u32CBL;
     /** Format (SDnFMT). */
-    uint16_t                 u16FMT;
+    uint16_t       u16FMT;
     /** FIFO Size (FIFOS).
      *  Maximum number of bytes that may have been DMA'd into
      *  memory but not yet transmitted on the link.
      *
      *  Must be a power of two. */
-    uint16_t                 u16FIFOS;
+    uint16_t       u16FIFOS;
     /** Last Valid Index (SDnLVI). */
-    uint16_t                 u16LVI;
-    uint16_t                 Padding1[3];
-    /** Pointer to HDA sink this stream is attached to. */
-    R3PTRTYPE(PHDAMIXERSINK) pMixSink;
+    uint16_t       u16LVI;
+    uint16_t       Padding1[3];
     /** Internal state of this stream. */
-    HDASTREAMSTATE           State;
+    HDASTREAMSTATE State;
 } HDASTREAM, *PHDASTREAM;
 
-/**
- * Structure for mapping a stream tag to an HDA stream.
- */
-typedef struct HDATAG
+typedef struct HDAINPUTSTREAM
 {
-    /** Own stream tag. */
-    uint8_t               uTag;
-    uint8_t               Padding[7];
-    /** Pointer to associated stream. */
-    R3PTRTYPE(PHDASTREAM) pStrm;
-} HDATAG, *PHDATAG;
+    /** PCM line input stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
+    /** Mixer handle for line input stream. */
+    R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
+} HDAINPUTSTREAM, *PHDAINPUTSTREAM;
 
-/**
- * Structure defining an HDA mixer stream.
- * This is being used together with an audio mixer instance.
- */
-typedef struct HDAMIXERSTREAM
+typedef struct HDAOUTPUTSTREAM
 {
-    union
-    {
-        /** Desired playback destination (for an output stream). */
-        PDMAUDIOPLAYBACKDEST           Dest;
-        /** Desired recording source (for an input stream). */
-        PDMAUDIORECSOURCE              Source;
-    } DestSource;
-    uint8_t                            Padding1[4];
-    /** Associated mixer handle. */
-    R3PTRTYPE(PAUDMIXSTREAM)           pMixStrm;
-} HDAMIXERSTREAM, *PHDAMIXERSTREAM;
+    /** PCM output stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
+    /** Mixer handle for line output stream. */
+    R3PTRTYPE(PAUDMIXSTREAM)           phStrmOut;
+} HDAOUTPUTSTREAM, *PHDAOUTPUTSTREAM;
 
 /**
  * Struct for maintaining a host backend driver.
@@ -750,20 +663,12 @@ typedef struct HDADRIVER
     R3PTRTYPE(PPDMIBASE)               pDrvBase;
     /** Audio connector interface to the underlying host backend. */
     R3PTRTYPE(PPDMIAUDIOCONNECTOR)     pConnector;
-    /** Mixer stream for line input. */
-    HDAMIXERSTREAM                     LineIn;
-#ifdef VBOX_WITH_HDA_MIC_IN
-    /** Mixer stream for mic input. */
-    HDAMIXERSTREAM                     MicIn;
-#endif
-    /** Mixer stream for front output. */
-    HDAMIXERSTREAM                     Front;
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    /** Mixer stream for center/LFE output. */
-    HDAMIXERSTREAM                     CenterLFE;
-    /** Mixer stream for rear output. */
-    HDAMIXERSTREAM                     Rear;
-#endif
+    /** Stream for line input. */
+    HDAINPUTSTREAM                     LineIn;
+    /** Stream for mic input. */
+    HDAINPUTSTREAM                     MicIn;
+    /** Stream for output. */
+    HDAOUTPUTSTREAM                    Out;
 } HDADRIVER;
 
 /**
@@ -772,7 +677,7 @@ typedef struct HDADRIVER
 typedef struct HDASTATE
 {
     /** The PCI device structure. */
-    PCIDevice                          PciDev;
+    PDMPCIDEV                          PciDev;
     /** R3 Pointer to the device instance. */
     PPDMDEVINSR3                       pDevInsR3;
     /** R0 Pointer to the device instance. */
@@ -785,11 +690,13 @@ typedef struct HDASTATE
     PDMIBASE                           IBase;
     RTGCPHYS                           MMIOBaseAddr;
     /** The HDA's register set. */
-    uint32_t                           au32Regs[HDA_NUM_REGS];
-    /** Internal stream states. */
-    HDASTREAM                          aStreams[HDA_MAX_STREAMS];
-    /** Mapping table between stream tags and stream states. */
-    HDATAG                             aTags[HDA_MAX_TAGS];
+    uint32_t                           au32Regs[HDA_NREGS];
+    /** Stream state for line-in. */
+    HDASTREAM                          StrmStLineIn;
+    /** Stream state for microphone-in. */
+    HDASTREAM                          StrmStMicIn;
+    /** Stream state for output. */
+    HDASTREAM                          StrmStOut;
     /** CORB buffer base address. */
     uint64_t                           u64CORBBase;
     /** RIRB buffer base address. */
@@ -800,7 +707,7 @@ typedef struct HDASTATE
     /** DMA position buffer enable bit. */
     bool                               fDMAPosition;
     /** Padding for alignment. */
-    uint8_t                            u8Padding0[7];
+    uint8_t                            u32Padding0[7];
     /** Pointer to CORB buffer. */
     R3PTRTYPE(uint32_t *)              pu32CorbBuf;
     /** Size in bytes of CORB buffer. */
@@ -811,21 +718,16 @@ typedef struct HDASTATE
     R3PTRTYPE(uint64_t *)              pu64RirbBuf;
     /** Size in bytes of RIRB buffer. */
     uint32_t                           cbRirbBuf;
-    /** Indicates if HDA controller is in reset mode. */
+    /** Indicates if HDA is in reset. */
     bool                               fInReset;
     /** Flag whether the R0 part is enabled. */
     bool                               fR0Enabled;
     /** Flag whether the RC part is enabled. */
     bool                               fRCEnabled;
-    /** Number of active (running) SDn streams. */
-    uint8_t                            cStreamsActive;
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     /** The timer for pumping data thru the attached LUN drivers. */
     PTMTIMERR3                         pTimer;
-    /** Flag indicating whether the timer is active or not. */
-    bool                               fTimerActive;
-    uint8_t                            u8Padding1[7];
-    /** Timer ticks per Hz. */
+    /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
     uint64_t                           cTimerTicks;
     /** Timestamp of the last timer callback (hdaTimer).
      * Used to calculate the time actually elapsed between two timer callbacks. */
@@ -844,20 +746,12 @@ typedef struct HDASTATE
     RTLISTANCHORR3                     lstDrv;
     /** The device' software mixer. */
     R3PTRTYPE(PAUDIOMIXER)             pMixer;
-    /** HDA sink for (front) output. */
-    HDAMIXERSINK                       SinkFront;
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    /** HDA sink for center / LFE output. */
-    HDAMIXERSINK                       SinkCenterLFE;
-    /** HDA sink for rear output. */
-    HDAMIXERSINK                       SinkRear;
-#endif
-    /** HDA mixer sink for line input. */
-    HDAMIXERSINK                       SinkLineIn;
-#ifdef VBOX_WITH_HDA_MIC_IN
+    /** Audio sink for PCM output. */
+    R3PTRTYPE(PAUDMIXSINK)             pSinkOutput;
+    /** Audio mixer sink for line input. */
+    R3PTRTYPE(PAUDMIXSINK)             pSinkLineIn;
     /** Audio mixer sink for microphone input. */
-    HDAMIXERSINK                       SinkMicIn;
-#endif
+    R3PTRTYPE(PAUDMIXSINK)             pSinkMicIn;
     uint64_t                           u64BaseTS;
     /** Response Interrupt Count (RINTCNT). */
     uint8_t                            u8RespIntCnt;
@@ -875,110 +769,79 @@ typedef struct HDACALLBACKCTX
 } HDACALLBACKCTX, *PHDACALLBACKCTX;
 #endif
 
-
 /*********************************************************************************************************************************
 *   Internal Functions                                                                                                           *
 *********************************************************************************************************************************/
 #ifndef VBOX_DEVICE_STRUCT_TESTCASE
-#ifdef IN_RING3
+# ifdef IN_RING3
 static FNPDMDEVRESET hdaReset;
 #endif
 
-/** @name Register read/write stubs.
- * @{
+/*
+ * Stubs.
  */
 static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
 static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-/** @} */
 
-/** @name Global register set read/write functions.
- * @{
+/*
+ * Global register set read/write functions.
  */
-static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
 static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
 static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-//static int hdaRegReadSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); - unused
-//static int hdaRegWriteSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);  - unused
-//static int hdaRegWriteINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - implementation not found.
-static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
 static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
 
-/** @name {IOB}SDn write functions.
- * @{
+/*
+ * {IOB}SDn read/write functions.
  */
-static int       hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int       hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int       hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int       hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-//static int       hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - unused
-//static int       hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - unused
-static int       hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int       hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int       hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
-
-/* Locking + logging. */
-#ifdef IN_RING3
-DECLINLINE(int)  hdaRegWriteSDLock(PHDASTATE pThis, PHDASTREAM pStream, uint32_t iReg, uint32_t u32Value);
-DECLINLINE(void) hdaRegWriteSDUnlock(PHDASTREAM pStream);
-#endif
+static int  hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int  hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+DECLINLINE(bool) hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 
-/** @name Generic register read/write functions.
- * @{
+/*
+ * Generic register read/write functions.
  */
 static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-#ifdef IN_RING3
-static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-#endif
+static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
-
-#ifdef IN_RING3
-static void hdaStreamDestroy(PHDASTREAM pStream);
-static int hdaStreamSetActive(PHDASTATE pThis, PHDASTREAM pStream, bool fActive);
-//static int hdaStreamStart(PHDASTREAM pStream); - unused
-static int hdaStreamStop(PHDASTREAM pStream);
-/*static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout); - currently unused */
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
-#endif
+static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
 
 #ifdef IN_RING3
-static int hdaStreamMapInit(PHDASTREAMMAPPING pMapping, PPDMAUDIOSTREAMCFG pCfg);
-static void hdaStreamMapDestroy(PHDASTREAMMAPPING pMapping);
-static void hdaStreamMapReset(PHDASTREAMMAPPING pMapping);
+static void hdaStreamDestroy(PHDASTREAM pStrmSt);
+//static int hdaStreamStart(PHDASTREAM pStrmSt);
+static int hdaStreamStop(PHDASTREAM pStrmSt);
+//static int hdaStreamWaitForStateChange(PHDASTREAM pStrmSt, RTMSINTERVAL msTimeout);
+static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed);
 #endif
 
 #ifdef IN_RING3
-static int           hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
-DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStream, uint32_t u32LPIB);
+static int       hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
+DECLINLINE(void) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t u32LPIB);
 # ifdef LOG_ENABLED
-static void          hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BaseDMA, uint16_t cBDLE);
+static void             hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BaseDMA, uint16_t cBDLE);
 # endif
 #endif
-static int           hdaProcessInterrupt(PHDASTATE pThis);
-
-/*
- * Timer routines.
- */
-#if !defined(VBOX_WITH_AUDIO_CALLBACKS) && defined(IN_RING3)
-static void hdaTimerMaybeStart(PHDASTATE pThis);
-static void hdaTimerMaybeStop(PHDASTATE pThis);
-#endif
 
 
 /*********************************************************************************************************************************
@@ -1012,9 +875,9 @@ static void hdaTimerMaybeStop(PHDASTATE pThis);
     /* Offset 0x8C (SD0) */ \
     { offset + 0xC,  0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16, hdaRegWriteSDLVI  , HDA_REG_IDX_STRM(name, LVI)  , #name " Last Valid Index" }, \
     /* Reserved: FIFO Watermark. ** @todo Document this! */ \
-    { offset + 0xE,  0x00002, 0x00000007, 0x00000007, hdaRegReadU16, hdaRegWriteU16,     HDA_REG_IDX_STRM(name, FIFOW), #name " FIFO Watermark" }, \
+    { offset + 0xE,  0x00002, 0x00000007, 0x00000007, hdaRegReadU16, hdaRegWriteSDFIFOW, HDA_REG_IDX_STRM(name, FIFOW), #name " FIFO Watermark" }, \
     /* Offset 0x90 (SD0) */ \
-    { offset + 0x10, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16, hdaRegWriteU16,     HDA_REG_IDX_STRM(name, FIFOS), #name " FIFO Size" }, \
+    { offset + 0x10, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16, hdaRegWriteSDFIFOS, HDA_REG_IDX_STRM(name, FIFOS), #name " FIFO Size" }, \
     /* Offset 0x92 (SD0) */ \
     { offset + 0x12, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16, hdaRegWriteSDFMT  , HDA_REG_IDX_STRM(name, FMT)  , #name " Stream Format" }, \
     /* Reserved: 0x94 - 0x98. */ \
@@ -1048,7 +911,7 @@ static const struct HDAREGDESC
     const char *abbrev;
     /** Descripton. */
     const char *desc;
-} g_aHdaRegMap[HDA_NUM_REGS] =
+} g_aHdaRegMap[HDA_NREGS] =
 
 {
     /* offset  size     read mask   write mask  read callback            write callback         index + abbrev   */
@@ -1056,13 +919,13 @@ static const struct HDAREGDESC
     { 0x00000, 0x00002, 0x0000FFFB, 0x00000000, hdaRegReadU16          , hdaRegWriteUnimpl     , HDA_REG_IDX(GCAP)         }, /* Global Capabilities */
     { 0x00002, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8           , hdaRegWriteUnimpl     , HDA_REG_IDX(VMIN)         }, /* Minor Version */
     { 0x00003, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8           , hdaRegWriteUnimpl     , HDA_REG_IDX(VMAJ)         }, /* Major Version */
-    { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16          , hdaRegWriteU16        , HDA_REG_IDX(OUTPAY)       }, /* Output Payload Capabilities */
+    { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16          , hdaRegWriteUnimpl     , HDA_REG_IDX(OUTPAY)       }, /* Output Payload Capabilities */
     { 0x00006, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16          , hdaRegWriteUnimpl     , HDA_REG_IDX(INPAY)        }, /* Input Payload Capabilities */
     { 0x00008, 0x00004, 0x00000103, 0x00000103, hdaRegReadU32          , hdaRegWriteGCTL       , HDA_REG_IDX(GCTL)         }, /* Global Control */
     { 0x0000c, 0x00002, 0x00007FFF, 0x00007FFF, hdaRegReadU16          , hdaRegWriteU16        , HDA_REG_IDX(WAKEEN)       }, /* Wake Enable */
     { 0x0000e, 0x00002, 0x00000007, 0x00000007, hdaRegReadU8           , hdaRegWriteSTATESTS   , HDA_REG_IDX(STATESTS)     }, /* State Change Status */
     { 0x00010, 0x00002, 0xFFFFFFFF, 0x00000000, hdaRegReadUnimpl       , hdaRegWriteUnimpl     , HDA_REG_IDX(GSTS)         }, /* Global Status */
-    { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16          , hdaRegWriteU16        , HDA_REG_IDX(OUTSTRMPAY)   }, /* Output Stream Payload Capability */
+    { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16          , hdaRegWriteUnimpl     , HDA_REG_IDX(OUTSTRMPAY)   }, /* Output Stream Payload Capability */
     { 0x0001A, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16          , hdaRegWriteUnimpl     , HDA_REG_IDX(INSTRMPAY)    }, /* Input Stream Payload Capability */
     { 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, hdaRegReadU32          , hdaRegWriteU32        , HDA_REG_IDX(INTCTL)       }, /* Interrupt Control */
     { 0x00024, 0x00004, 0xC00000FF, 0x00000000, hdaRegReadINTSTS       , hdaRegWriteUnimpl     , HDA_REG_IDX(INTSTS)       }, /* Interrupt Status */
@@ -1087,12 +950,12 @@ static const struct HDAREGDESC
     { 0x00068, 0x00002, 0x00000002, 0x00000002, hdaRegReadIRS          , hdaRegWriteIRS        , HDA_REG_IDX(IRS)          }, /* Immediate Command Status */
     { 0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, hdaRegReadU32          , hdaRegWriteBase       , HDA_REG_IDX(DPLBASE)      }, /* DMA Position Lower Base */
     { 0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32          , hdaRegWriteBase       , HDA_REG_IDX(DPUBASE)      }, /* DMA Position Upper Base */
-    /* 4 Serial Data In (SDI). */
+    /* 4 Input Stream Descriptors (ISD). */
     HDA_REG_MAP_DEF_STREAM(0, SD0),
     HDA_REG_MAP_DEF_STREAM(1, SD1),
     HDA_REG_MAP_DEF_STREAM(2, SD2),
     HDA_REG_MAP_DEF_STREAM(3, SD3),
-    /* 4 Serial Data Out (SDO). */
+    /* 4 Output Stream Descriptors (OSD). */
     HDA_REG_MAP_DEF_STREAM(4, SD4),
     HDA_REG_MAP_DEF_STREAM(5, SD5),
     HDA_REG_MAP_DEF_STREAM(6, SD6),
@@ -1162,33 +1025,34 @@ static uint32_t const g_afMasks[5] =
 };
 
 #ifdef IN_RING3
-
-DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStream, uint32_t u32LPIB)
+DECLINLINE(void) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t u32LPIB)
 {
-    AssertPtrReturn(pThis,   0);
-    AssertPtrReturn(pStream, 0);
+    AssertPtrReturnVoid(pThis);
+    AssertPtrReturnVoid(pStrmSt);
 
-    Assert(u32LPIB <= pStream->u32CBL);
+    Assert(u32LPIB <= pStrmSt->u32CBL);
 
     LogFlowFunc(("[SD%RU8]: LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
-                 pStream->u8SD, u32LPIB, pThis->fDMAPosition));
+                 pStrmSt->u8Strm, u32LPIB, pThis->fDMAPosition));
 
     /* Update LPIB in any case. */
-    HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) = u32LPIB;
+    HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) = u32LPIB;
 
     /* Do we need to tell the current DMA position? */
     if (pThis->fDMAPosition)
     {
         int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
-                                        (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStream->u8SD * 2 * sizeof(uint32_t)),
+                                        (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStrmSt->u8Strm * 2 * sizeof(uint32_t)),
                                         (void *)&u32LPIB, sizeof(uint32_t));
         AssertRC(rc2);
+#ifdef DEBUG
+        hdaBDLEDumpAll(pThis, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
+#endif
     }
-
-    return u32LPIB;
 }
+#endif
 
-
+#if defined(IN_RING3) || defined(LOG_ENABLED)
 /**
  * Retrieves the number of bytes of a FIFOS register.
  *
@@ -1200,16 +1064,16 @@ DECLINLINE(uint16_t) hdaSDFIFOSToBytes(uint32_t u32RegFIFOS)
     switch (u32RegFIFOS)
     {
         /* Input */
-        case HDA_SDIFIFO_120B: cb = 120; break;
-        case HDA_SDIFIFO_160B: cb = 160; break;
+        case HDA_SDINFIFO_120B: cb = 120; break;
+        case HDA_SDINFIFO_160B: cb = 160; break;
 
         /* Output */
-        case HDA_SDOFIFO_16B:  cb = 16;  break;
-        case HDA_SDOFIFO_32B:  cb = 32;  break;
-        case HDA_SDOFIFO_64B:  cb = 64;  break;
-        case HDA_SDOFIFO_128B: cb = 128; break;
-        case HDA_SDOFIFO_192B: cb = 192; break;
-        case HDA_SDOFIFO_256B: cb = 256; break;
+        case HDA_SDONFIFO_16B:  cb = 16;  break;
+        case HDA_SDONFIFO_32B:  cb = 32;  break;
+        case HDA_SDONFIFO_64B:  cb = 64;  break;
+        case HDA_SDONFIFO_128B: cb = 128; break;
+        case HDA_SDONFIFO_192B: cb = 192; break;
+        case HDA_SDONFIFO_256B: cb = 256; break;
         default:
         {
             cb = 0; /* Can happen on stream reset. */
@@ -1219,9 +1083,9 @@ DECLINLINE(uint16_t) hdaSDFIFOSToBytes(uint32_t u32RegFIFOS)
 
     return cb;
 }
+#endif
 
-
-# if defined(IN_RING3) && (defined(DEBUG) || defined(VBOX_HDA_WITH_FIFO))
+#if defined(IN_RING3) && (defined(VBOX_HDA_WITH_FIFO) || defined(DEBUG))
 /**
  * Retrieves the number of bytes of a FIFOW register.
  *
@@ -1238,111 +1102,92 @@ DECLINLINE(uint8_t) hdaSDFIFOWToBytes(uint32_t u32RegFIFOW)
         default:              cb = 0;  break;
     }
 
+#ifdef RT_STRICT
     Assert(RT_IS_POWER_OF_TWO(cb));
+#endif
     return cb;
 }
 #endif
 
-
+#ifdef IN_RING3
 /**
  * Fetches the next BDLE to use for a stream.
  *
  * @return  IPRT status code.
  */
-DECLINLINE(int) hdaStreamGetNextBDLE(PHDASTATE pThis, PHDASTREAM pStream)
+DECLINLINE(int) hdaStreamGetNextBDLE(PHDASTATE pThis, PHDASTREAM pStrmSt)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
     NOREF(pThis);
 
-    Assert(pStream->State.uCurBDLE < pStream->u16LVI + 1);
-
-    LogFlowFuncEnter();
-
-# ifdef LOG_ENABLED
-    uint32_t const uOldBDLE = pStream->State.uCurBDLE;
-# endif
+    Assert(pStrmSt->State.uCurBDLE < pStrmSt->u16LVI + 1);
 
-    PHDABDLE pBDLE = &pStream->State.BDLE;
+#ifdef DEBUG
+    uint32_t uOldBDLE = pStrmSt->State.uCurBDLE;
+#endif
 
     /*
      * Switch to the next BDLE entry and do a wrap around
      * if we reached the end of the Buffer Descriptor List (BDL).
      */
-    pStream->State.uCurBDLE++;
-    if (pStream->State.uCurBDLE == pStream->u16LVI + 1)
+    pStrmSt->State.uCurBDLE++;
+    if (pStrmSt->State.uCurBDLE == pStrmSt->u16LVI + 1)
     {
-        pStream->State.uCurBDLE = 0;
+        pStrmSt->State.uCurBDLE = 0;
 
-        hdaStreamUpdateLPIB(pThis, pStream, 0);
+        hdaStreamUpdateLPIB(pThis, pStrmSt, 0);
     }
 
-    Assert(pStream->State.uCurBDLE < pStream->u16LVI + 1);
+    Assert(pStrmSt->State.uCurBDLE < pStrmSt->u16LVI + 1);
 
-    /* Fetch the next BDLE entry. */
-    int rc = hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+    int rc = hdaBDLEFetch(pThis, &pStrmSt->State.BDLE, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
 
-    LogFlowFunc(("[SD%RU8]: uOldBDLE=%RU16, uCurBDLE=%RU16, LVI=%RU32, rc=%Rrc, %R[bdle]\n",
-                 pStream->u8SD, uOldBDLE, pStream->State.uCurBDLE, pStream->u16LVI, rc, pBDLE));
+#ifdef DEBUG
+    LogFlowFunc(("[SD%RU8]: uOldBDLE=%RU16, uCurBDLE=%RU16, LVI=%RU32, %R[bdle]\n",
+                 pStrmSt->u8Strm, uOldBDLE, pStrmSt->State.uCurBDLE, pStrmSt->u16LVI, &pStrmSt->State.BDLE));
+#endif
     return rc;
 }
+#endif
 
-
-/**
- * Returns the audio direction of a specified stream descriptor.
- *
- * The register layout specifies that input streams (SDI) come first,
- * followed by the output streams (SDO). So every stream ID below HDA_MAX_SDI
- * is an input stream, whereas everything >= HDA_MAX_SDI is an output stream.
- *
- * Note: SDnFMT register does not provide that information, so we have to judge
- *       for ourselves.
- *
- * @return  Audio direction.
- */
-DECLINLINE(PDMAUDIODIR) hdaGetDirFromSD(uint8_t uSD)
-{
-    AssertReturn(uSD <= HDA_MAX_STREAMS, PDMAUDIODIR_UNKNOWN);
-
-    if (uSD < HDA_MAX_SDI)
-        return PDMAUDIODIR_IN;
-
-    return PDMAUDIODIR_OUT;
-}
-
-
-/**
- * Returns the HDA stream of specified stream descriptor number.
- *
- * @return  Pointer to HDA stream, or NULL if none found.
- */
-DECLINLINE(PHDASTREAM) hdaStreamFromSD(PHDASTATE pThis, uint8_t uSD)
+DECLINLINE(PHDASTREAM) hdaStreamFromID(PHDASTATE pThis, uint8_t uStreamID)
 {
-    AssertPtrReturn(pThis, NULL);
-    AssertReturn(uSD <= HDA_MAX_STREAMS, NULL);
-
-    if (uSD >= HDA_MAX_STREAMS)
-        return NULL;
-
-    return &pThis->aStreams[uSD];
-}
+    PHDASTREAM pStrmSt;
 
+    switch (uStreamID)
+    {
+        case 0: /** @todo Use dynamic indices, based on stream assignment. */
+        {
+            pStrmSt = &pThis->StrmStLineIn;
+            break;
+        }
+# ifdef VBOX_WITH_HDA_MIC_IN
+        case 2: /** @todo Use dynamic indices, based on stream assignment. */
+        {
+            pStrmSt = &pThis->StrmStMicIn;
+            break;
+        }
+# endif
+        case 4: /** @todo Use dynamic indices, based on stream assignment. */
+        {
+            pStrmSt = &pThis->StrmStOut;
+            break;
+        }
 
-/**
- * Returns the HDA stream of specified HDA sink.
- *
- * @return  Pointer to HDA stream, or NULL if none found.
- */
-DECLINLINE(PHDASTREAM) hdaGetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink)
-{
-    AssertPtrReturn(pThis, NULL);
-    AssertPtrReturn(pSink, NULL);
+        default:
+        {
+            pStrmSt = NULL;
+            LogFunc(("Warning: Stream with ID=%RU8 not handled\n", uStreamID));
+            break;
+        }
+    }
 
-    /** @todo Do something with the channel mapping here? */
-    return hdaStreamFromSD(pThis, pSink->uSD);
+    return pStrmSt;
 }
 
+#ifdef IN_RING3
 /**
  * Retrieves the minimum number of bytes accumulated/free in the
  * FIFO before the controller will start a fetch/eviction of data.
@@ -1351,19 +1196,18 @@ DECLINLINE(PHDASTREAM) hdaGetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink
  *
  * @return Number of bytes accumulated/free in the FIFO.
  */
-DECLINLINE(uint8_t) hdaStreamGetFIFOW(PHDASTATE pThis, PHDASTREAM pStream)
+DECLINLINE(uint8_t) hdaStreamGetFIFOW(PHDASTATE pThis, PHDASTREAM pStrmSt)
 {
     AssertPtrReturn(pThis, 0);
-    AssertPtrReturn(pStream, 0);
+    AssertPtrReturn(pStrmSt, 0);
 
 # ifdef VBOX_HDA_WITH_FIFO
-    return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStream->u8SD));
+    return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStrmSt->u8Strm));
 # else
     return 0;
 # endif
 }
-
-#endif /* IN_RING3 */
+#endif
 
 static int hdaProcessInterrupt(PHDASTATE pThis)
 {
@@ -1371,35 +1215,29 @@ static int hdaProcessInterrupt(PHDASTATE pThis)
         (   INTCTL_SX((pThis), num) \
          && (SDSTS(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
 
-    int iLevel = 0;
-
-    /** @todo Optimize IRQ handling. */
+    bool fIrq = false;
 
     if (/* Controller Interrupt Enable (CIE). */
           HDA_REG_FLAG_VALUE(pThis, INTCTL, CIE)
        && (   HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)
            || HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
            || (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN))))
-    {
-        iLevel = 1;
-    }
+        fIrq = true;
 
+    /** @todo Don't hardcode stream numbers here. */
     if (   IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 0)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 1)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 2)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 3)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 5)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 6)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 7))
+        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4))
     {
-        iLevel = 1;
+#ifdef IN_RING3
+        LogFunc(("BCIS\n"));
+#endif
+        fIrq = true;
     }
 
     if (HDA_REG_FLAG_VALUE(pThis, INTCTL, GIE))
     {
-        Log3Func(("Level=%d\n", iLevel));
-        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , iLevel);
+        LogFunc(("%s\n", fIrq ? "Asserted" : "Deasserted"));
+        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , fIrq);
     }
 
 #undef IS_INTERRUPT_OCCURED_AND_ENABLED
@@ -1513,21 +1351,16 @@ static int hdaRegLookupWithin(uint32_t offReg)
 }
 
 #ifdef IN_RING3
-
 static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
 {
     int rc = VINF_SUCCESS;
     if (fLocal)
     {
         Assert((HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)));
-        Assert(pThis->u64CORBBase);
-        AssertPtr(pThis->pu32CorbBuf);
-        Assert(pThis->cbCorbBuf);
-
         rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
         if (RT_FAILURE(rc))
             AssertRCReturn(rc, rc);
-# ifdef DEBUG_CMD_BUFFER
+#ifdef DEBUG_CMD_BUFFER
         uint8_t i = 0;
         do
         {
@@ -1548,7 +1381,7 @@ static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
             LogFunc(("\n"));
             i += 8;
         } while(i != 0);
-# endif
+#endif
     }
     else
     {
@@ -1556,7 +1389,7 @@ static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
         rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf);
         if (RT_FAILURE(rc))
             AssertRCReturn(rc, rc);
-# ifdef DEBUG_CMD_BUFFER
+#ifdef DEBUG_CMD_BUFFER
         uint8_t i = 0;
         do {
             LogFunc(("RIRB%02x: ", i));
@@ -1572,13 +1405,15 @@ static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
             LogFunc(("\n"));
             i += 8;
         } while (i != 0);
-# endif
+#endif
     }
     return rc;
 }
 
 static int hdaCORBCmdProcess(PHDASTATE pThis)
 {
+    PFNHDACODECVERBPROCESSOR pfn = (PFNHDACODECVERBPROCESSOR)NULL;
+
     int rc = hdaCmdSync(pThis, true);
     if (RT_FAILURE(rc))
         AssertRCReturn(rc, rc);
@@ -1588,41 +1423,46 @@ static int hdaCORBCmdProcess(PHDASTATE pThis)
     uint8_t rirbWp = HDA_REG(pThis, RIRBWP);
 
     Assert((corbWp != corbRp));
-    Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
+    LogFlowFunc(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
 
     while (corbRp != corbWp)
     {
-        uint64_t uResp;
-        uint32_t uCmd = pThis->pu32CorbBuf[++corbRp];
+        uint32_t cmd;
+        uint64_t resp = 0;
+        pfn = NULL;
+        corbRp++;
+        cmd = pThis->pu32CorbBuf[corbRp];
 
-        int rc2 = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp);
-        if (RT_FAILURE(rc2))
-            LogFunc(("Codec lookup failed with rc=%Rrc\n", rc2));
+        rc = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(cmd, 0 /* Codec index */), &pfn);
+        if (RT_SUCCESS(rc))
+        {
+            AssertPtr(pfn);
+            rc = pfn(pThis->pCodec, HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
+        }
 
+        AssertRCReturn(rc, rc);
         (rirbWp)++;
 
-        if (   (uResp & CODEC_RESPONSE_UNSOLICITED)
+        LogFunc(("verb:%08x->%016lx\n", cmd, resp));
+        if (   (resp & CODEC_RESPONSE_UNSOLICITED)
             && !HDA_REG_FLAG_VALUE(pThis, GCTL, UR))
         {
-            LogFunc(("Unexpected unsolicited response\n"));
+            LogFunc(("unexpected unsolicited response.\n"));
             HDA_REG(pThis, CORBRP) = corbRp;
             return rc;
         }
 
-        pThis->pu64RirbBuf[rirbWp] = uResp;
+        pThis->pu64RirbBuf[rirbWp] = resp;
 
         pThis->u8RespIntCnt++;
         if (pThis->u8RespIntCnt == RINTCNT_N(pThis))
             break;
     }
-
     HDA_REG(pThis, CORBRP) = corbRp;
     HDA_REG(pThis, RIRBWP) = rirbWp;
-
     rc = hdaCmdSync(pThis, false);
-
-    Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
-
+    LogFunc(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP),
+         HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
     if (HDA_REG_FLAG_VALUE(pThis, RIRBCTL, RIC))
     {
         HDA_REG(pThis, RIRBSTS) |= HDA_REG_FIELD_FLAG_MASK(RIRBSTS,RINTFL);
@@ -1630,263 +1470,164 @@ static int hdaCORBCmdProcess(PHDASTATE pThis)
         pThis->u8RespIntCnt = 0;
         rc = hdaProcessInterrupt(pThis);
     }
-
     if (RT_FAILURE(rc))
         AssertRCReturn(rc, rc);
     return rc;
 }
 
-static int hdaStreamCreate(PHDASTREAM pStream, uint8_t uSD)
+static int hdaStreamCreate(PHDASTREAM pStrmSt)
 {
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(uSD <= HDA_MAX_STREAMS, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-    int rc = RTSemEventCreate(&pStream->State.hStateChangedEvent);
-    if (RT_SUCCESS(rc))
-        rc = RTCritSectInit(&pStream->State.CritSect);
+    int rc = RTSemEventCreate(&pStrmSt->State.hStateChangedEvent);
+    AssertRC(rc);
 
-    if (RT_SUCCESS(rc))
-    {
-        pStream->u8SD           = uSD;
-        pStream->pMixSink       = NULL;
+    pStrmSt->u8Strm         = UINT8_MAX;
 
-        pStream->State.fActive  = false;
-        pStream->State.fInReset = false;
-        pStream->State.fDoStop  = false;
-    }
+    pStrmSt->State.fActive  = false;
+    pStrmSt->State.fInReset = false;
+    pStrmSt->State.fDoStop  = false;
 
-    LogFlowFunc(("uSD=%RU8\n", uSD));
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-static void hdaStreamDestroy(PHDASTREAM pStream)
+static void hdaStreamDestroy(PHDASTREAM pStrmSt)
 {
-    AssertPtrReturnVoid(pStream);
-
-    LogFlowFunc(("[SD%RU8]: Destroying ...\n", pStream->u8SD));
+    AssertPtrReturnVoid(pStrmSt);
 
-    int rc2 = hdaStreamStop(pStream);
-    AssertRC(rc2);
-
-    hdaStreamMapDestroy(&pStream->State.Mapping);
+    LogFlowFunc(("[SD%RU8]: Destroy\n", pStrmSt->u8Strm));
 
-    rc2 = RTCritSectDelete(&pStream->State.CritSect);
+    int rc2 = hdaStreamStop(pStrmSt);
     AssertRC(rc2);
 
-    if (pStream->State.hStateChangedEvent != NIL_RTSEMEVENT)
+    if (pStrmSt->State.hStateChangedEvent != NIL_RTSEMEVENT)
     {
-        rc2 = RTSemEventDestroy(pStream->State.hStateChangedEvent);
+        rc2 = RTSemEventDestroy(pStrmSt->State.hStateChangedEvent);
         AssertRC(rc2);
-        pStream->State.hStateChangedEvent = NIL_RTSEMEVENT;
     }
 
     LogFlowFuncLeave();
 }
 
-static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStream, uint8_t u8SD)
+static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-    pStream->u8SD       = u8SD;
-    pStream->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStream->u8SD),
-                                      HDA_STREAM_REG(pThis, BDPU, pStream->u8SD));
-    pStream->u16LVI     = HDA_STREAM_REG(pThis, LVI, pStream->u8SD);
-    pStream->u32CBL     = HDA_STREAM_REG(pThis, CBL, pStream->u8SD);
-    pStream->u16FIFOS   = hdaSDFIFOSToBytes(HDA_STREAM_REG(pThis, FIFOS, pStream->u8SD));
+    pStrmSt->u8Strm     = u8Strm;
+    pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrmSt->u8Strm),
+                                      HDA_STREAM_REG(pThis, BDPU, pStrmSt->u8Strm));
+    pStrmSt->u16LVI     = HDA_STREAM_REG(pThis, LVI, pStrmSt->u8Strm);
+    pStrmSt->u32CBL     = HDA_STREAM_REG(pThis, CBL, pStrmSt->u8Strm);
+    pStrmSt->u16FIFOS   = hdaSDFIFOSToBytes(HDA_STREAM_REG(pThis, FIFOS, pStrmSt->u8Strm));
 
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
-
-    hdaStreamMapReset(&pStream->State.Mapping);
+    RT_ZERO(pStrmSt->State.BDLE);
+    pStrmSt->State.uCurBDLE = 0;
 
     LogFlowFunc(("[SD%RU8]: DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16\n",
-                 pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS));
+                 pStrmSt->u8Strm, pStrmSt->u64BDLBase, pStrmSt->u32CBL, pStrmSt->u16LVI, pStrmSt->u16FIFOS));
 
-# ifdef DEBUG
-    uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStream->u8SD),
-                                      HDA_STREAM_REG(pThis, BDPU, pStream->u8SD));
-    uint16_t u16LVI     = HDA_STREAM_REG(pThis, LVI, pStream->u8SD);
-    uint32_t u32CBL     = HDA_STREAM_REG(pThis, CBL, pStream->u8SD);
+#ifdef DEBUG
+    uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
+                                      HDA_STREAM_REG(pThis, BDPU, u8Strm));
+    uint16_t u16LVI     = HDA_STREAM_REG(pThis, LVI, u8Strm);
+    uint32_t u32CBL     = HDA_STREAM_REG(pThis, CBL, u8Strm);
 
     LogFlowFunc(("\t-> DMA @ 0x%x, LVI=%RU16, CBL=%RU32\n", u64BaseDMA, u16LVI, u32CBL));
 
     hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
-# endif
+#endif
 
     return VINF_SUCCESS;
 }
 
-static void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream)
+static void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
 {
     AssertPtrReturnVoid(pThis);
-    AssertPtrReturnVoid(pStream);
-
-    const uint8_t uSD = pStream->u8SD;
+    AssertPtrReturnVoid(pStrmSt);
+    AssertReturnVoid(u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
 
-# ifdef VBOX_STRICT
-    AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, uSD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)),
-                     ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
-# endif
-
-    LogFunc(("[SD%RU8]: Reset\n", uSD));
+#ifdef VBOX_STRICT
+    AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)),
+                     ("Cannot reset stream %RU8 while in running state\n", u8Strm));
+#endif
 
     /*
      * Set reset state.
      */
-    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false); /* No nested calls. */
-    ASMAtomicXchgBool(&pStream->State.fInReset, true);
+    Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false); /* No nested calls. */
+    ASMAtomicXchgBool(&pStrmSt->State.fInReset, true);
 
     /*
      * First, reset the internal stream state.
      */
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
+    RT_BZERO(pStrmSt, sizeof(HDASTREAM));
 
     /*
      * Second, initialize the registers.
      */
-    HDA_STREAM_REG(pThis, STS,   uSD) = HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+    HDA_STREAM_REG(pThis, STS,   u8Strm) = 0;
     /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
      * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
-    HDA_STREAM_REG(pThis, CTL,   uSD) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
+    HDA_STREAM_REG(pThis, CTL,   u8Strm) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
     /* ICH6 defines default values (0x77 for input and 0xBF for output descriptors) of FIFO size. 18.2.39. */
-    HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDIFIFO_120B : HDA_SDOFIFO_192B;
+    HDA_STREAM_REG(pThis, FIFOS, u8Strm) = u8Strm < 4 ? HDA_SDINFIFO_120B : HDA_SDONFIFO_192B;
     /* See 18.2.38: Always defaults to 0x4 (32 bytes). */
-    HDA_STREAM_REG(pThis, FIFOW, uSD) = HDA_SDFIFOW_32B;
-    HDA_STREAM_REG(pThis, LPIB,  uSD) = 0;
-    HDA_STREAM_REG(pThis, CBL,   uSD) = 0;
-    HDA_STREAM_REG(pThis, LVI,   uSD) = 0;
-    HDA_STREAM_REG(pThis, FMT,   uSD) = HDA_SDFMT_MAKE(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
-                                                       HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
-                                                       HDA_SDFMT_CHAN_STEREO);
-    HDA_STREAM_REG(pThis, BDPU,  uSD) = 0;
-    HDA_STREAM_REG(pThis, BDPL,  uSD) = 0;
-
-    int rc2 = hdaStreamInit(pThis, pStream, uSD);
-    AssertRC(rc2);
-
-    /* Report that we're done resetting this stream. */
-    HDA_STREAM_REG(pThis, CTL,   uSD) = 0;
-
-    /* Exit reset state. */
-    ASMAtomicXchgBool(&pStream->State.fInReset, false);
-}
-
-# if 0 /* unused */
-static bool hdaStreamIsActive(PHDASTATE pThis, PHDASTREAM pStream)
-{
-    AssertPtrReturn(pThis,   false);
-    AssertPtrReturn(pStream, false);
-
-    bool fActive = pStream->State.fActive;
-
-    LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive));
-    return fActive;
-}
-# endif
-
-static int hdaStreamSetActive(PHDASTATE pThis, PHDASTREAM pStream, bool fActive)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    LogFlowFunc(("[SD%RU8]: fActive=%RTbool, pMixSink=%p\n", pStream->u8SD, fActive, pStream->pMixSink));
-
-    if (pStream->State.fActive == fActive) /* No change required? */
-    {
-        LogFlowFunc(("[SD%RU8]: No change\n", pStream->u8SD));
-        return VINF_SUCCESS;
-    }
-
-    int rc = VINF_SUCCESS;
-
-    if (pStream->pMixSink) /* Stream attached to a sink? */
-    {
-        AUDMIXSINKCMD enmCmd = fActive
-                             ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-
-        /* First, enable or disable the stream and the stream's sink, if any. */
-        if (pStream->pMixSink->pMixSink)
-            rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
-    }
-    else
-        rc = VINF_SUCCESS;
-
-    if (RT_FAILURE(rc))
-    {
-        LogFlowFunc(("Failed with rc=%Rrc\n", rc));
-        return rc;
-    }
-
-    pStream->State.fActive = fActive;
-
-    /* Second, see if we need to start or stop the timer. */
-    if (!fActive)
-    {
-        if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
-            pThis->cStreamsActive--;
+    HDA_STREAM_REG(pThis, FIFOW, u8Strm) = HDA_SDFIFOW_32B;
+    HDA_STREAM_REG(pThis, LPIB,  u8Strm) = 0;
+    HDA_STREAM_REG(pThis, CBL,   u8Strm) = 0;
+    HDA_STREAM_REG(pThis, LVI,   u8Strm) = 0;
+    HDA_STREAM_REG(pThis, FMT,   u8Strm) = 0;
+    HDA_STREAM_REG(pThis, BDPU,  u8Strm) = 0;
+    HDA_STREAM_REG(pThis, BDPL,  u8Strm) = 0;
 
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
-        hdaTimerMaybeStop(pThis);
-# endif
-    }
-    else
-    {
-        pThis->cStreamsActive++;
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
-        hdaTimerMaybeStart(pThis);
-# endif
-    }
+    /*
+     * Third, set the internal state according to the just set registers.
+     */
+    pStrmSt->u8Strm   = u8Strm;
+    pStrmSt->u16FIFOS = HDA_STREAM_REG(pThis, FIFOS, u8Strm);
 
-    LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool, cStreamsActive=%RU8\n", pStream->u8SD, fActive, pThis->cStreamsActive));
-    return VINF_SUCCESS;
-}
 
-static void hdaStreamAssignToSink(PHDASTREAM pStream, PHDAMIXERSINK pMixSink)
-{
-    AssertPtrReturnVoid(pStream);
+    /* Report that we're done resetting this stream. */
+    HDA_STREAM_REG(pThis, CTL,   u8Strm) = 0;
 
-    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
-    if (RT_SUCCESS(rc2))
-    {
-        pStream->pMixSink = pMixSink;
+    LogFunc(("[SD%RU8]: Reset\n", u8Strm));
 
-        rc2 = RTCritSectLeave(&pStream->State.CritSect);
-        AssertRC(rc2);
-    }
+    /* Exit reset mode. */
+    ASMAtomicXchgBool(&pStrmSt->State.fInReset, false);
 }
 
-# if 0 /** @todo hdaStreamStart is unused */
-static int hdaStreamStart(PHDASTREAM pStream)
+#if 0 // unused
+static int hdaStreamStart(PHDASTREAM pStrmSt)
 {
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-    ASMAtomicXchgBool(&pStream->State.fDoStop, false);
-    ASMAtomicXchgBool(&pStream->State.fActive, true);
+    ASMAtomicXchgBool(&pStrmSt->State.fDoStop, false);
+    ASMAtomicXchgBool(&pStrmSt->State.fActive, true);
 
     LogFlowFuncLeave();
     return VINF_SUCCESS;
 }
-# endif /* unused */
+#endif
 
-static int hdaStreamStop(PHDASTREAM pStream)
+static int hdaStreamStop(PHDASTREAM pStrmSt)
 {
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
     /* Already in stopped state? */
-    bool fActive = ASMAtomicReadBool(&pStream->State.fActive);
+    bool fActive = ASMAtomicReadBool(&pStrmSt->State.fActive);
     if (!fActive)
         return VINF_SUCCESS;
 
-# if 0 /** @todo Does not work (yet), as EMT deadlocks then. */
+#if 0 /** @todo Does not work (yet), as EMT deadlocks then. */
     /*
      * Wait for the stream to stop.
      */
-    ASMAtomicXchgBool(&pStream->State.fDoStop, true);
+    ASMAtomicXchgBool(&pStrmSt->State.fDoStop, true);
 
-    int rc = hdaStreamWaitForStateChange(pStream, 60 * 1000 /* ms timeout */);
-    fActive = ASMAtomicReadBool(&pStream->State.fActive);
+    int rc = hdaStreamWaitForStateChange(pStrmSt, 60 * 1000 /* ms timeout */);
+    fActive = ASMAtomicReadBool(&pStrmSt->State.fActive);
     if (   /* Waiting failed? */
            RT_FAILURE(rc)
            /* Stream is still active? */
@@ -1894,167 +1635,50 @@ static int hdaStreamStop(PHDASTREAM pStream)
     {
         AssertRC(rc);
         LogRel(("HDA: Warning: Unable to stop stream %RU8 (state: %s), rc=%Rrc\n",
-                pStream->u8Strm, fActive ? "active" : "stopped", rc));
+                pStrmSt->u8Strm, fActive ? "active" : "stopped", rc));
     }
-# else
+#else
     int rc = VINF_SUCCESS;
-# endif
+#endif
 
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-# if defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND)
-static int hdaStreamChannelExtract(PPDMAUDIOSTREAMCHANNEL pChan, const void *pvBuf, size_t cbBuf)
+#if 0 // unused
+static int hdaStreamWaitForStateChange(PHDASTREAM pStrmSt, RTMSINTERVAL msTimeout)
 {
-    AssertPtrReturn(pChan, VERR_INVALID_POINTER);
-    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
-    AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
-
-    AssertRelease(pChan->cbOff <= cbBuf);
-
-    const uint8_t *pu8Buf = (const uint8_t *)pvBuf;
-
-    size_t         cbSrc = cbBuf - pChan->cbOff;
-    const uint8_t *pvSrc = &pu8Buf[pChan->cbOff];
-
-    size_t         cbDst;
-    uint8_t       *pvDst;
-    RTCircBufAcquireWriteBlock(pChan->Data.pCircBuf, cbBuf, (void **)&pvDst, &cbDst);
-
-    cbSrc = RT_MIN(cbSrc, cbDst);
-
-    while (cbSrc)
-    {
-        AssertBreak(cbDst >= cbSrc);
-
-        /* Enough data for at least one next frame? */
-        if (cbSrc < pChan->cbFrame)
-            break;
-
-        memcpy(pvDst, pvSrc, pChan->cbFrame);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-        /* Advance to next channel frame in stream. */
-        pvSrc        += pChan->cbStep;
-        Assert(cbSrc >= pChan->cbStep);
-        cbSrc        -= pChan->cbStep;
-
-        /* Advance destination by one frame. */
-        pvDst        += pChan->cbFrame;
-        Assert(cbDst >= pChan->cbFrame);
-        cbDst        -= pChan->cbFrame;
-
-        /* Adjust offset. */
-        pChan->cbOff += pChan->cbFrame;
-    }
+    LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStrmSt->u8Strm, msTimeout));
+    return RTSemEventWait(pStrmSt->State.hStateChangedEvent, msTimeout);
+}
+#endif
+#endif /* IN_RING3 */
 
-    RTCircBufReleaseWriteBlock(pChan->Data.pCircBuf, cbDst);
+/* Register access handlers. */
 
+static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
+{
+    RT_NOREF(pThis, iReg);
+    *pu32Value = 0;
     return VINF_SUCCESS;
 }
-# endif /* defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND) */
 
-# if 0 /** @todo hdaStreamChannelAdvance is unused */
-static int hdaStreamChannelAdvance(PPDMAUDIOSTREAMCHANNEL pChan, size_t cbAdv)
+static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    AssertPtrReturn(pChan, VERR_INVALID_POINTER);
-
-    if (!cbAdv)
-        return VINF_SUCCESS;
-
+    RT_NOREF(pThis, iReg, u32Value);
     return VINF_SUCCESS;
 }
-# endif
 
-static int hdaStreamChannelDataInit(PPDMAUDIOSTREAMCHANNELDATA pChanData, uint32_t fFlags)
+/* U8 */
+static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
-    int rc = RTCircBufCreate(&pChanData->pCircBuf, 256); /** @todo Make this configurable? */
-    if (RT_SUCCESS(rc))
-    {
-        pChanData->fFlags = fFlags;
-    }
-
-    return rc;
+    Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0);
+    return hdaRegReadU32(pThis, iReg, pu32Value);
 }
 
-/**
- * Frees a stream channel data block again.
- *
- * @param   pChanData           Pointer to channel data to free.
- */
-static void hdaStreamChannelDataDestroy(PPDMAUDIOSTREAMCHANNELDATA pChanData)
-{
-    if (!pChanData)
-        return;
-
-    if (pChanData->pCircBuf)
-    {
-        RTCircBufDestroy(pChanData->pCircBuf);
-        pChanData->pCircBuf = NULL;
-    }
-
-    pChanData->fFlags = PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE;
-}
-
-# if defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND)
-
-static int hdaStreamChannelAcquireData(PPDMAUDIOSTREAMCHANNELDATA pChanData, void *pvData, size_t *pcbData)
-{
-    AssertPtrReturn(pChanData, VERR_INVALID_POINTER);
-    AssertPtrReturn(pvData,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pcbData,   VERR_INVALID_POINTER);
-
-    RTCircBufAcquireReadBlock(pChanData->pCircBuf, 256 /** @todo Make this configurarble? */, &pvData, &pChanData->cbAcq);
-
-    *pcbData = pChanData->cbAcq;
-    return VINF_SUCCESS;
-}
-
-static int hdaStreamChannelReleaseData(PPDMAUDIOSTREAMCHANNELDATA pChanData)
-{
-    AssertPtrReturn(pChanData, VERR_INVALID_POINTER);
-    RTCircBufReleaseReadBlock(pChanData->pCircBuf, pChanData->cbAcq);
-
-    return VINF_SUCCESS;
-}
-
-# endif /* defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND) */
-
-# if 0 /* currently unused */
-static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStream->u8SD, msTimeout));
-    return RTSemEventWait(pStream->State.hStateChangedEvent, msTimeout);
-}
-# endif /* currently unused */
-
-#endif /* IN_RING3 */
-
-/* Register access handlers. */
-
-static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg);
-    *pu32Value = 0;
-    return VINF_SUCCESS;
-}
-
-static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
-    return VINF_SUCCESS;
-}
-
-/* U8 */
-static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
-    Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0);
-    return hdaRegReadU32(pThis, iReg, pu32Value);
-}
-
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
     Assert((u32Value & 0xffffff00) == 0);
     return hdaRegWriteU32(pThis, iReg, u32Value);
@@ -2080,13 +1704,11 @@ static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
     return hdaRegReadU32(pThis, iReg, pu32Value);
 }
 
-#ifdef IN_RING3
 static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
     Assert((u32Value & 0xff000000) == 0);
     return hdaRegWriteU32(pThis, iReg, u32Value);
 }
-#endif
 
 /* U32 */
 static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
@@ -2108,8 +1730,7 @@ static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 
 static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, RST))
     {
         /* Set the CRST bit to indicate that we're leaving reset mode. */
@@ -2117,7 +1738,7 @@ static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 
         if (pThis->fInReset)
         {
-            LogFunc(("Guest leaving HDA reset\n"));
+            LogFunc(("Leaving reset\n"));
             pThis->fInReset = false;
         }
     }
@@ -2125,20 +1746,24 @@ static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
     {
 #ifdef IN_RING3
         /* Enter reset state. */
-        LogFunc(("Guest entering HDA reset with DMA(RIRB:%s, CORB:%s)\n",
-                 HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) ? "on" : "off",
-                 HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA) ? "on" : "off"));
+        if (   HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)
+            || HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA))
+        {
+            LogFunc(("Entering reset with DMA(RIRB:%s, CORB:%s)\n",
+                     HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) ? "on" : "off",
+                     HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA) ? "on" : "off"));
+        }
 
-        /* Clear the CRST bit to indicate that we're in reset state. */
+        /* Clear the CRST bit to indicate that we're in reset mode. */
         HDA_REG(pThis, GCTL) &= ~HDA_REG_FIELD_FLAG_MASK(GCTL, RST);
         pThis->fInReset = true;
 
+        /* As the CRST bit now is set, we now can proceed resetting stuff. */
         hdaReset(pThis->CTX_SUFF(pDevIns));
 #else
         return VINF_IOM_R3_MMIO_WRITE;
 #endif
     }
-
     if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, FSH))
     {
         /* Flush: GSTS:1 set, see 6.2.6. */
@@ -2160,8 +1785,7 @@ static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value
 
 static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     uint32_t v = 0;
     if (   HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
         || HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)
@@ -2171,30 +1795,26 @@ static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
         v |= RT_BIT(30); /* Touch CIS. */
     }
 
-#define HDA_MARK_STREAM(x)                                             \
-    if (/* Descriptor Error */                                         \
-           (SDSTS((pThis), x) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE))    \
-        /* FIFO Error */                                               \
-        || (SDSTS((pThis), x) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE))    \
-        /* Buffer Completion Interrupt Status */                       \
-        || (SDSTS((pThis), x) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) \
-    {                                                                  \
-        Log3Func(("[SD%RU8] BCIS: Marked\n", x));                      \
-        v |= RT_BIT(x);                                                \
-    }
+#define HDA_IS_STREAM_EVENT(pThis, num)                                  \
+       (   (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE))    \
+        || (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE))    \
+        || (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
+
+#define HDA_MARK_STREAM(pThis, num, v) \
+        do { (v) |= HDA_IS_STREAM_EVENT((pThis), num) ? RT_BIT((num)) : 0; } while(0)
 
-    HDA_MARK_STREAM(0);
-    HDA_MARK_STREAM(1);
-    HDA_MARK_STREAM(2);
-    HDA_MARK_STREAM(3);
-    HDA_MARK_STREAM(4);
-    HDA_MARK_STREAM(5);
-    HDA_MARK_STREAM(6);
-    HDA_MARK_STREAM(7);
+    HDA_MARK_STREAM(pThis, 0, v);
+    HDA_MARK_STREAM(pThis, 1, v);
+    HDA_MARK_STREAM(pThis, 2, v);
+    HDA_MARK_STREAM(pThis, 3, v);
+    HDA_MARK_STREAM(pThis, 4, v);
+    HDA_MARK_STREAM(pThis, 5, v);
+    HDA_MARK_STREAM(pThis, 6, v);
+    HDA_MARK_STREAM(pThis, 7, v);
 
+#undef HDA_IS_STREAM_EVENT
 #undef HDA_MARK_STREAM
 
-    /* "OR" bit of all interrupt status bits. */
     v |= v ? RT_BIT(31) : 0;
 
     *pu32Value = v;
@@ -2205,10 +1825,8 @@ static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
     const uint8_t  u8Strm  = HDA_SD_NUM_FROM_REG(pThis, LPIB, iReg);
     uint32_t       u32LPIB = HDA_STREAM_REG(pThis, LPIB, u8Strm);
-#ifdef LOG_ENABLED
-    const uint32_t u32CBL  = HDA_STREAM_REG(pThis, CBL,  u8Strm);
-    LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32\n", u8Strm, u32LPIB, u32CBL));
-#endif
+
+    LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32\n", u8Strm, u32LPIB, HDA_STREAM_REG(pThis, CBL,  u8Strm)));
 
     *pu32Value = u32LPIB;
     return VINF_SUCCESS;
@@ -2216,8 +1834,7 @@ static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 
 static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */
     *pu32Value = (uint32_t)ASMMultU64ByU32DivByU32(PDMDevHlpTMTimeVirtGetNano(pThis->CTX_SUFF(pDevIns))
                                                    - pThis->u64BaseTS, 24, 1000);
@@ -2225,30 +1842,9 @@ static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
     return VINF_SUCCESS;
 }
 
-#if 0 /** @todo hdaRegReadSSYNC &  hdaRegWriteSSYNC are unused */
-
-static int hdaRegReadSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
-    RT_NOREF_PV(iReg);
-
-    /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */
-    *pu32Value = HDA_REG(pThis, SSYNC);
-    LogFlowFunc(("%RU32\n", *pu32Value));
-    return VINF_SUCCESS;
-}
-
-static int hdaRegWriteSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-    LogFlowFunc(("%RU32\n", u32Value));
-    return hdaRegWriteU32(pThis, iReg, u32Value);
-}
-
-#endif /* unused */
-
 static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     if (u32Value & HDA_REG_FIELD_FLAG_MASK(CORBRP, RST))
     {
         HDA_REG(pThis, CORBRP) = 0;
@@ -2272,15 +1868,14 @@ static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
     }
     return rc;
 #else
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
+    RT_NOREF(pThis, iReg, u32Value);
     return VINF_IOM_R3_MMIO_WRITE;
 #endif
 }
 
 static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     uint32_t v = HDA_REG(pThis, CORBSTS);
     HDA_REG(pThis, CORBSTS) &= ~(v & u32Value);
     return VINF_SUCCESS;
@@ -2299,236 +1894,179 @@ static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
         return VINF_SUCCESS;
     rc = hdaCORBCmdProcess(pThis);
     return rc;
-#else  /* !IN_RING3 */
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
+#else
+    RT_NOREF(pThis, iReg, u32Value);
     return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+#endif
 }
 
 static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-#ifdef IN_RING3
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
-        return VINF_SUCCESS;
-
-    PHDASTREAM pStream = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, CBL, iReg));
-    if (!pStream)
+    int rc = hdaRegWriteU32(pThis, iReg, u32Value);
+    if (RT_SUCCESS(rc))
     {
-        LogFunc(("[SD%RU8]: Warning: Changing SDCBL on non-attached stream (0x%x)\n", HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), u32Value));
-        return hdaRegWriteU32(pThis, iReg, u32Value);
-    }
+        uint8_t u8Strm  = HDA_SD_NUM_FROM_REG(pThis, CBL, iReg);
 
-    int rc2 = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
-    AssertRC(rc2);
-
-    pStream->u32CBL = u32Value;
-
-    /* Reset BDLE state. */
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
+        PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+        if (pStrmSt)
+        {
+            pStrmSt->u32CBL = u32Value;
 
-    rc2 = hdaRegWriteU32(pThis, iReg, u32Value);
-    AssertRC(rc2);
+            /* Reset BDLE state. */
+            RT_ZERO(pStrmSt->State.BDLE);
+            pStrmSt->State.uCurBDLE = 0;
+        }
 
-    LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", pStream->u8SD, u32Value));
-    hdaRegWriteSDUnlock(pStream);
+        LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
+    }
+    else
+        AssertRCReturn(rc, VINF_SUCCESS);
 
-    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-#else  /* !IN_RING3 */
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+    return rc;
 }
 
 static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-#ifdef IN_RING3
-    bool fRun      = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-    bool fInRun    = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-
-    bool fReset    = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
-    bool fInReset  = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
-
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
-        return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+#if defined(LOG_ENABLED) || defined(IN_RING3)
+    bool const fRun      = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+    bool const fInRun    = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+#endif
+    bool const fReset    = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
+    bool const fInReset  = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
 
-    /* Get the stream descriptor. */
-    uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
+    uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
 
-    /*
-     * Extract the stream tag the guest wants to use for this specific
-     * stream descriptor (SDn). This only can happen if the stream is in a non-running
-     * state, so we're doing the lookup and assignment here.
-     *
-     * So depending on the guest OS, SD3 can use stream tag 4, for example.
-     */
-    uint8_t uTag = (u32Value >> HDA_SDCTL_NUM_SHIFT) & HDA_SDCTL_NUM_MASK;
-    if (uTag > HDA_MAX_TAGS)
+    PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+    if (!pStrmSt)
     {
-        LogFunc(("[SD%RU8]: Warning: Invalid stream tag %RU8 specified!\n", uSD, uTag));
-        return hdaRegWriteU24(pThis, iReg, u32Value);
+        LogFunc(("Warning: Changing SDCTL on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
+        return hdaRegWriteU24(pThis, iReg, u32Value); /* Write 3 bytes. */
     }
 
-    PHDATAG pTag = &pThis->aTags[uTag];
-    AssertPtr(pTag);
-
-    LogFunc(("[SD%RU8]: Using stream tag=%RU8\n", uSD, uTag));
-
-    /* Assign new values. */
-    pTag->uTag  = uTag;
-    pTag->pStrm = hdaStreamFromSD(pThis, uSD);
-
-    PHDASTREAM pStream = pTag->pStrm;
-    AssertPtr(pStream);
-
-    /* Note: Do not use hdaRegWriteSDLock() here, as SDnCTL might change the RUN bit. */
-    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
-    AssertRC(rc2);
-
     LogFunc(("[SD%RU8]: fRun=%RTbool, fInRun=%RTbool, fReset=%RTbool, fInReset=%RTbool, %R[sdctl]\n",
-             uSD, fRun, fInRun, fReset, fInReset, u32Value));
+             u8Strm, fRun, fInRun, fReset, fInReset, u32Value));
 
     if (fInReset)
     {
+        /* Guest is resetting HDA's stream, we're expecting guest will mark stream as exit. */
         Assert(!fReset);
-        Assert(!fInRun && !fRun);
-
-        /* Report that we're done resetting this stream by clearing SRST. */
-        HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST);
-
-        LogFunc(("[SD%RU8]: Guest initiated exit of stream reset\n", uSD));
+        LogFunc(("Guest initiated exit of stream reset\n"));
     }
     else if (fReset)
     {
+#ifdef IN_RING3
         /* ICH6 datasheet 18.2.33 says that RUN bit should be cleared before initiation of reset. */
         Assert(!fInRun && !fRun);
 
-        LogFunc(("[SD%RU8]: Guest initiated enter to stream reset\n", pStream->u8SD));
-        hdaStreamReset(pThis, pStream);
+        LogFunc(("Guest initiated enter to stream reset\n"));
+        hdaStreamReset(pThis, pStrmSt, u8Strm);
+#else
+        return VINF_IOM_R3_MMIO_WRITE;
+#endif
     }
     else
     {
+#ifdef IN_RING3
         /*
          * We enter here to change DMA states only.
          */
         if (fInRun != fRun)
         {
             Assert(!fReset && !fInReset);
-            LogFunc(("[SD%RU8]: fRun=%RTbool\n", pStream->u8SD, fRun));
-
-            hdaStreamSetActive(pThis, pStream, fRun);
+            LogFunc(("[SD%RU8]: fRun=%RTbool\n", u8Strm, fRun));
 
-            if (fRun)
+            PHDADRIVER pDrv;
+            switch (u8Strm)
             {
-                /* (Re-)Fetch the current BDLE entry. */
-                rc2 = hdaBDLEFetch(pThis, &pStream->State.BDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
-                AssertRC(rc2);
+                case 0: /** @todo Use a variable here. Later. */
+                {
+                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+                                                      pDrv->LineIn.pStrmIn, fRun);
+                    break;
+                }
+# ifdef VBOX_WITH_HDA_MIC_IN
+                case 2: /** @todo Use a variable here. Later. */
+                {
+                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+                                                      pDrv->MicIn.pStrmIn, fRun);
+                    break;
+                }
+# endif
+                case 4: /** @todo Use a variable here. Later. */
+                {
+                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                        pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+                                                       pDrv->Out.pStrmOut, fRun);
+                    break;
+                }
+                default:
+                    AssertMsgFailed(("Changing RUN bit on non-attached stream, register %RU32\n", iReg));
+                    break;
             }
         }
 
         if (!fInRun && !fRun)
-            hdaStreamInit(pThis, pStream, pStream->u8SD);
-    }
+            hdaStreamInit(pThis, pStrmSt, u8Strm);
 
-    /* Make sure to handle interrupts here as well. */
-    hdaProcessInterrupt(pThis);
-
-    rc2 = hdaRegWriteU24(pThis, iReg, u32Value);
-    AssertRC(rc2);
+#else /* IN_RING3 */
+        return VINF_IOM_R3_MMIO_WRITE;
+#endif /* !IN_RING3 */
+    }
 
-    hdaRegWriteSDUnlock(pStream);
-    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-#else  /* !IN_RING3 */
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+    return hdaRegWriteU24(pThis, iReg, u32Value);
 }
 
 static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    uint32_t v  = HDA_REG_IND(pThis, iReg);
-             /* Clear (zero) FIFOE and DESE bits when writing 1 to it. */
-             v &= ~(u32Value & v);
-
+    uint32_t v = HDA_REG_IND(pThis, iReg);
+    v &= ~(u32Value & v);
     HDA_REG_IND(pThis, iReg) = v;
-
     hdaProcessInterrupt(pThis);
     return VINF_SUCCESS;
 }
 
 static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-#ifdef IN_RING3
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+    if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
         return VINF_SUCCESS;
 
-    PHDASTREAM pStream = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, LVI, iReg));
-    if (!pStream)
+    int rc = hdaRegWriteU16(pThis, iReg, u32Value);
+    if (RT_SUCCESS(rc))
     {
-        LogFunc(("[SD%RU8]: Warning: Changing SDLVI on non-attached stream (0x%x)\n", HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), u32Value));
-        return hdaRegWriteU16(pThis, iReg, u32Value);
-    }
-
-    int rc2 = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
-    AssertRC(rc2);
-
-    /** @todo Validate LVI. */
-    pStream->u16LVI = u32Value;
+        uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
 
-    /* Reset BDLE state. */
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
-
-    rc2 = hdaRegWriteU16(pThis, iReg, u32Value);
-    AssertRC(rc2);
+        PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+        if (pStrmSt)
+        {
+            pStrmSt->u16LVI = u32Value;
 
-    LogFlowFunc(("[SD%RU8]: LVI=%RU32\n", pStream->u8SD, u32Value));
-    hdaRegWriteSDUnlock(pStream);
+            /* Reset BDLE state. */
+            RT_ZERO(pStrmSt->State.BDLE);
+            pStrmSt->State.uCurBDLE = 0;
+        }
 
-    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+        LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
+    }
+    else
+        AssertRCReturn(rc, VINF_SUCCESS);
 
-#else  /* !IN_RING3 */
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+    return rc;
 }
 
-#if 0 /** @todo hdaRegWriteSDFIFOW & hdaRegWriteSDFIFOS are unused */
 static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    uint8_t  uSD      = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg);
-    /** @todo Only allow updating FIFOS if RUN bit is 0? */
-    uint32_t u32FIFOW = 0;
-
-    if (hdaGetDirFromSD(uSD) != PDMAUDIODIR_IN) /* FIFOW for input streams only. */
-    {
-        LogRel(("HDA: Warning: Guest tried to write read-only FIFOW to stream #%RU8, ignoring\n", uSD));
-        return VINF_SUCCESS;
-    }
-
     switch (u32Value)
     {
         case HDA_SDFIFOW_8B:
         case HDA_SDFIFOW_16B:
         case HDA_SDFIFOW_32B:
-            u32FIFOW = u32Value;
-            break;
+            return hdaRegWriteU16(pThis, iReg, u32Value);
         default:
-            LogRel(("HDA: Warning: Guest tried write unsupported FIFOW (0x%x) to stream #%RU8, defaulting to 32 bytes\n",
-                    u32Value, uSD));
-            u32FIFOW = HDA_SDFIFOW_32B;
-            break;
-    }
-
-    if (u32FIFOW)
-    {
-        LogFunc(("[SD%RU8]: Updating FIFOW to %RU32 bytes\n", uSD, hdaSDFIFOSToBytes(u32FIFOW)));
-        /** @todo Update internal stream state with new FIFOS. */
-
-        return hdaRegWriteU16(pThis, iReg, u32FIFOW);
+            LogFunc(("Attempt to store unsupported value(%x) in SDFIFOW\n", u32Value));
+            return hdaRegWriteU16(pThis, iReg, HDA_SDFIFOW_32B);
     }
-
-    return VINF_SUCCESS; /* Never reached. */
 }
 
 /**
@@ -2537,40 +2075,55 @@ static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
  */
 static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    uint8_t  uSD      = HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg);
     /** @todo Only allow updating FIFOS if RUN bit is 0? */
     uint32_t u32FIFOS = 0;
 
-    if (hdaGetDirFromSD(uSD) != PDMAUDIODIR_OUT) /* FIFOS for output streams only. */
-    {
-        LogRel(("HDA: Warning: Guest tried to write read-only FIFOS to stream #%RU8, ignoring\n", uSD));
-        return VINF_SUCCESS;
-    }
-
-    switch(u32Value)
+    switch (iReg)
     {
-        case HDA_SDOFIFO_16B:
-        case HDA_SDOFIFO_32B:
-        case HDA_SDOFIFO_64B:
-        case HDA_SDOFIFO_128B:
-        case HDA_SDOFIFO_192B:
-            u32FIFOS = u32Value;
+        /* SDInFIFOS is RO, n=0-3. */
+        case HDA_REG_SD0FIFOS:
+        case HDA_REG_SD1FIFOS:
+        case HDA_REG_SD2FIFOS:
+        case HDA_REG_SD3FIFOS:
+        {
+            LogFunc(("Guest tries to change R/O value of FIFO size of input stream, ignoring\n"));
             break;
+        }
+        case HDA_REG_SD4FIFOS:
+        case HDA_REG_SD5FIFOS:
+        case HDA_REG_SD6FIFOS:
+        case HDA_REG_SD7FIFOS:
+        {
+            switch(u32Value)
+            {
+                case HDA_SDONFIFO_16B:
+                case HDA_SDONFIFO_32B:
+                case HDA_SDONFIFO_64B:
+                case HDA_SDONFIFO_128B:
+                case HDA_SDONFIFO_192B:
+                    u32FIFOS = u32Value;
+                    break;
+
+                case HDA_SDONFIFO_256B: /** @todo r=andy Investigate this. */
+                    LogFunc(("256-bit is unsupported, HDA is switched into 192-bit mode\n"));
+                    /* Fall through is intentional. */
+                default:
+                    u32FIFOS = HDA_SDONFIFO_192B;
+                    break;
+            }
 
-        case HDA_SDOFIFO_256B: /** @todo r=andy Investigate this. */
-            LogFunc(("256-bit is unsupported, HDA is switched into 192-bit mode\n"));
-            /* Fall through is intentional. */
+            break;
+        }
         default:
-            LogRel(("HDA: Warning: Guest tried write unsupported FIFOS (0x%x) to stream #%RU8, defaulting to 192 bytes\n",
-                    u32Value, uSD));
-            u32FIFOS = HDA_SDOFIFO_192B;
+        {
+            AssertMsgFailed(("Something weird happened with register lookup routine\n"));
             break;
+        }
     }
 
     if (u32FIFOS)
     {
-        LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n",
-                 HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg), hdaSDFIFOSToBytes(u32FIFOS)));
+        LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n", 0, hdaSDFIFOSToBytes(u32FIFOS)));
         /** @todo Update internal stream state with new FIFOS. */
 
         return hdaRegWriteU16(pThis, iReg, u32FIFOS);
@@ -2579,19 +2132,16 @@ static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
     return VINF_SUCCESS;
 }
 
-#endif /* unused */
-
-#ifdef IN_RING3
-static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pStrmCfg)
+#if defined(IN_RING3) && defined(VBOX_WITH_HDA_CODEC_EMU)
+static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pCfg)
 {
-    AssertPtrReturn(pStrmCfg, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
 
 # define EXTRACT_VALUE(v, mask, shift) ((v & ((mask) << (shift))) >> (shift))
 
     int rc = VINF_SUCCESS;
 
-    uint32_t u32Hz     = EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BASE_RATE_MASK, HDA_SDFMT_BASE_RATE_SHIFT)
-                       ? 44100 : 48000;
+    uint32_t u32Hz     = (u32SDFMT & HDA_SDFMT_BASE_RATE_SHIFT) ? 44100 : 48000;
     uint32_t u32HzMult = 1;
     uint32_t u32HzDiv  = 1;
 
@@ -2624,350 +2174,121 @@ static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pStrmCfg)
             break;
     }
 
-    PDMAUDIOFMT enmFmt;
+    PDMAUDIOFMT enmFmt = AUD_FMT_S16; /* Default to 16-bit signed. */
     switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))
     {
         case 0:
-            enmFmt = PDMAUDIOFMT_S8;
+            LogFunc(("Requested 8-bit\n"));
+            enmFmt = AUD_FMT_S8;
             break;
         case 1:
-            enmFmt = PDMAUDIOFMT_S16;
+            LogFunc(("Requested 16-bit\n"));
+            enmFmt = AUD_FMT_S16;
+            break;
+        case 2:
+            LogFunc(("Requested 20-bit\n"));
+            break;
+        case 3:
+            LogFunc(("Requested 24-bit\n"));
             break;
         case 4:
-            enmFmt = PDMAUDIOFMT_S32;
+            LogFunc(("Requested 32-bit\n"));
+            enmFmt = AUD_FMT_S32;
             break;
         default:
-            AssertMsgFailed(("Unsupported bits per sample %x\n",
+            AssertMsgFailed(("Unsupported bits shift %x\n",
                              EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)));
-            enmFmt = PDMAUDIOFMT_INVALID;
             rc = VERR_NOT_SUPPORTED;
             break;
     }
 
     if (RT_SUCCESS(rc))
     {
-        pStrmCfg->uHz           = u32Hz * u32HzMult / u32HzDiv;
-        pStrmCfg->cChannels     = (u32SDFMT & 0xf) + 1;
-        pStrmCfg->enmFormat     = enmFmt;
-        pStrmCfg->enmEndianness = PDMAUDIOHOSTENDIANNESS;
+        pCfg->uHz           = u32Hz * u32HzMult / u32HzDiv;
+        pCfg->cChannels     = (u32SDFMT & 0xf) + 1;
+        pCfg->enmFormat     = enmFmt;
+        pCfg->enmEndianness = PDMAUDIOHOSTENDIANNESS;
     }
 
 # undef EXTRACT_VALUE
+
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
+#endif
 
-static int hdaAddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
+static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
-
-    AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
-
-    LogFlowFunc(("Stream=%s\n", pCfg->szName));
-
-    int rc = VINF_SUCCESS;
-
-    bool fUseFront = true; /* Always use front out by default. */
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    bool fUseRear;
-    bool fUseCenter;
-    bool fUseLFE;
+#ifdef IN_RING3
+# ifdef VBOX_WITH_HDA_CODEC_EMU
+    /* No reason to re-open stream with same settings. */
+    if (u32Value == HDA_REG_IND(pThis, iReg))
+        return VINF_SUCCESS;
 
-    fUseRear = fUseCenter = fUseLFE = false;
+    PDMAUDIOSTREAMCFG strmCfg;
+    int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);
+    if (RT_FAILURE(rc))
+        return VINF_SUCCESS; /* Always return success to the MMIO handler. */
 
-    /*
-     * Use commonly used setups for speaker configurations.
-     */
+    uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, FMT, iReg);
 
-    /** @todo Make the following configurable through mixer API and/or CFGM? */
-    switch (pCfg->cChannels)
+    PHDADRIVER pDrv;
+    switch (iReg)
     {
-        case 3:  /* 2.1: Front (Stereo) + LFE. */
-        {
-            fUseLFE   = true;
-            break;
-        }
-
-        case 4:  /* Quadrophonic: Front (Stereo) + Rear (Stereo). */
-        {
-            fUseRear  = true;
+        case HDA_REG_SD0FMT:
+            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                rc = hdaCodecOpenStream(pThis->pCodec, PI_INDEX, &strmCfg);
             break;
-        }
-
-        case 5:  /* 4.1: Front (Stereo) + Rear (Stereo) + LFE. */
-        {
-            fUseRear  = true;
-            fUseLFE   = true;
+#  ifdef VBOX_WITH_HDA_MIC_IN
+        case HDA_REG_SD2FMT:
+            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                rc = hdaCodecOpenStream(pThis->pCodec, MC_INDEX, &strmCfg);
             break;
-        }
-
-        case 6:  /* 5.1: Front (Stereo) + Rear (Stereo) + Center/LFE. */
-        {
-            fUseRear   = true;
-            fUseCenter = true;
-            fUseLFE    = true;
+#  endif
+        case HDA_REG_SD4FMT:
+            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                rc = hdaCodecOpenStream(pThis->pCodec, PO_INDEX, &strmCfg);
             break;
-        }
-
-        default: /* Unknown; fall back to 2 front channels (stereo). */
-        {
-            rc = VERR_NOT_SUPPORTED;
+        default:
+            LogFunc(("Warning: Changing SDFMT on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
             break;
-        }
-    }
-#else /* !VBOX_WITH_HDA_51_SURROUND */
-    /* Only support mono or stereo channels. */
-    if (   pCfg->cChannels != 1 /* Mono */
-        && pCfg->cChannels != 2 /* Stereo */)
-    {
-        rc = VERR_NOT_SUPPORTED;
     }
-#endif
 
-    if (rc == VERR_NOT_SUPPORTED)
-    {
-        LogRel(("HDA: Unsupported channel count (%RU8), falling back to stereo channels\n", pCfg->cChannels));
-        pCfg->cChannels = 2;
+    /** @todo r=andy rc gets lost; needs fixing. */
+    return hdaRegWriteU16(pThis, iReg, u32Value);
+# else /* !VBOX_WITH_HDA_CODEC_EMU */
+    return hdaRegWriteU16(pThis, iReg, u32Value);
+# endif
+#else /* !IN_RING3 */
+    RT_NOREF(pThis, iReg, u32Value);
+    return VINF_IOM_R3_MMIO_WRITE;
+#endif
+}
 
-        rc = VINF_SUCCESS;
-    }
+/* Note: Will be called for both, BDPL and BDPU, registers. */
+DECLINLINE(int) hdaRegWriteSDBDPX(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t u8Strm)
+{
+    if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
+        return VINF_SUCCESS;
 
-    do
+    int rc = hdaRegWriteU32(pThis, iReg, u32Value);
+    if (RT_SUCCESS(rc))
     {
-        if (RT_FAILURE(rc))
-            break;
-
-        if (fUseFront)
+        PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+        if (pStrmSt)
         {
-            RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Front");
-            pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
-            pCfg->cChannels       = 2;
-
-            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_FRONT);
-            if (RT_SUCCESS(rc))
-                rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT, pCfg);
+            pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
+                                              HDA_STREAM_REG(pThis, BDPU, u8Strm));
+            /* Reset BDLE state. */
+            RT_ZERO(pStrmSt->State.BDLE);
+            pStrmSt->State.uCurBDLE = 0;
         }
+    }
+    else
+        AssertRCReturn(rc, VINF_SUCCESS);
 
-#ifdef VBOX_WITH_HDA_51_SURROUND
-        if (   RT_SUCCESS(rc)
-            && (fUseCenter || fUseLFE))
-        {
-            RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Center/LFE");
-            pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
-            pCfg->cChannels       = (fUseCenter && fUseLFE) ? 2 : 1;
-
-            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_CENTER_LFE);
-            if (RT_SUCCESS(rc))
-                rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
-        }
-
-        if (   RT_SUCCESS(rc)
-            && fUseRear)
-        {
-            RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Rear");
-            pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
-            pCfg->cChannels       = 2;
-
-            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_REAR);
-            if (RT_SUCCESS(rc))
-                rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR, pCfg);
-        }
-#endif /* VBOX_WITH_HDA_51_SURROUND */
-
-    } while (0);
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-static int hdaAddStreamIn(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
-
-    AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER);
-
-    LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Source));
-
-    int rc;
-
-    switch (pCfg->DestSource.Source)
-    {
-        case PDMAUDIORECSOURCE_LINE:
-        {
-            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_LINE_IN);
-            if (RT_SUCCESS(rc))
-                rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
-            break;
-        }
-#ifdef VBOX_WITH_HDA_MIC_IN
-        case PDMAUDIORECSOURCE_MIC:
-        {
-            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_MIC_IN);
-            if (RT_SUCCESS(rc))
-                rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
-            break;
-        }
-#endif
-        default:
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    LogFlowFuncLeaveRC(rc);
     return rc;
 }
-#endif /* IN_RING3 */
-
-static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#ifdef IN_RING3
-    PDMAUDIOSTREAMCFG strmCfg;
-    RT_ZERO(strmCfg);
-
-    int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);
-    if (RT_FAILURE(rc))
-        return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-
-    PHDASTREAM pStream = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, FMT, iReg));
-    if (!pStream)
-    {
-        LogFunc(("[SD%RU8]: Warning: Changing SDFMT on non-attached stream (0x%x)\n",
-                 HDA_SD_NUM_FROM_REG(pThis, FMT, iReg), u32Value));
-        return hdaRegWriteU16(pThis, iReg, u32Value);
-    }
-
-    int rcSem = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
-    AssertRC(rcSem);
-
-    LogFunc(("[SD%RU8]: Hz=%RU32, Channels=%RU8, enmFmt=%RU32\n",
-             pStream->u8SD, strmCfg.uHz, strmCfg.cChannels, strmCfg.enmFormat));
-
-    /* Set audio direction. */
-    strmCfg.enmDir = hdaGetDirFromSD(pStream->u8SD);
-    switch (strmCfg.enmDir)
-    {
-        case PDMAUDIODIR_IN:
-# ifdef VBOX_WITH_HDA_MIC_IN
-#  error "Implement me!"
-# else
-            strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
-            RTStrCopy(strmCfg.szName, sizeof(strmCfg.szName), "Line In");
-# endif
-            break;
-
-        case PDMAUDIODIR_OUT:
-            /* Destination(s) will be set in hdaAddStreamOut(),
-             * based on the channels / stream layout. */
-            break;
-
-        default:
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    /*
-     * Initialize the stream mapping in any case, regardless if
-     * we support surround audio or not. This is needed to handle
-     * the supported channels within a single audio stream, e.g. mono/stereo.
-     *
-     * In other words, the stream mapping *always* knowns the real
-     * number of channels in a single audio stream.
-     */
-    if (RT_SUCCESS(rc))
-    {
-        rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);
-        AssertRC(rc);
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        PHDADRIVER pDrv;
-        RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
-        {
-            int rc2;
-            switch (strmCfg.enmDir)
-            {
-                case PDMAUDIODIR_OUT:
-                    rc2 = hdaAddStreamOut(pThis, &strmCfg);
-                    break;
-
-                case PDMAUDIODIR_IN:
-                    rc2 = hdaAddStreamIn(pThis, &strmCfg);
-                    break;
-
-                default:
-                    rc2 = VERR_NOT_SUPPORTED;
-                    AssertFailed();
-                    break;
-            }
-
-            if (   RT_FAILURE(rc2)
-                && (pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY)) /* We only care about primary drivers here, the rest may fail. */
-            {
-                if (RT_SUCCESS(rc))
-                    rc = rc2;
-                /* Keep going. */
-            }
-        }
-
-        /* If (re-)opening the stream by the codec above failed, don't write the new
-         * format to the register so that the guest is aware it didn't work. */
-        if (RT_SUCCESS(rc))
-        {
-            rc = hdaRegWriteU16(pThis, iReg, u32Value);
-            AssertRC(rc);
-        }
-        else
-            LogFunc(("[SD%RU8]: (Re-)Opening stream failed with rc=%Rrc\n", pStream->u8SD, rc));
-    }
-
-    if (RT_SUCCESS(rcSem))
-        hdaRegWriteSDUnlock(pStream);
-
-    return VINF_SUCCESS; /* Never return failure. */
-#else /* !IN_RING3 */
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif
-}
-
-/* Note: Will be called for both, BDPL and BDPU, registers. */
-DECLINLINE(int) hdaRegWriteSDBDPX(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t u8Strm)
-{
-#ifdef IN_RING3
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
-        return VINF_SUCCESS;
-
-    PHDASTREAM pStream = hdaStreamFromSD(pThis, u8Strm);
-    if (!pStream)
-    {
-        LogFunc(("[SD%RU8]: Warning: Changing SDBPL/SDBPU on non-attached stream (0x%x)\n", HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), u32Value));
-        return hdaRegWriteU32(pThis, iReg, u32Value);
-    }
-
-    int rc2 = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
-    AssertRC(rc2);
-
-    rc2 = hdaRegWriteU32(pThis, iReg, u32Value);
-    AssertRC(rc2);
-
-    /* Update BDL base. */
-    pStream->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
-                                      HDA_STREAM_REG(pThis, BDPU, u8Strm));
-    /* Reset BDLE state. */
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
-
-    LogFlowFunc(("[SD%RU8]: BDLBase=0x%x\n", pStream->u8SD, pStream->u64BDLBase));
-    hdaRegWriteSDUnlock(pStream);
-
-    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-#else  /* !IN_RING3 */
-    RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value); RT_NOREF_PV(u8Strm);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
-}
 
 static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
@@ -2979,64 +2300,48 @@ static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
     return hdaRegWriteSDBDPX(pThis, iReg, u32Value, HDA_SD_NUM_FROM_REG(pThis, BDPU, iReg));
 }
 
-#ifdef IN_RING3
 /**
- * XXX
- *
- * @return  VBox status code.  ALL THE CALLERS IGNORES THIS. DUH.
+ * Checks whether a write to a specific SDnXXX register is allowed or not.
  *
+ * @return  bool                Returns @true if write is allowed, @false if not.
  * @param   pThis               Pointer to HDA state.
- * @param   iReg                Register to write (logging only).
- * @param   u32Value            Value to write (logging only).
+ * @param   iReg                Register to write.
+ * @param   u32Value            Value to write.
  */
-DECLINLINE(int) hdaRegWriteSDLock(PHDASTATE pThis, PHDASTREAM pStream, uint32_t iReg, uint32_t u32Value)
+DECLINLINE(bool) hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF(pThis, iReg, u32Value);
-    AssertPtr(pThis);   /* don't bother returning errors */
-    AssertPtr(pStream);
+    RT_NOREF(u32Value);
 
-# ifdef VBOX_STRICT
     /* Check if the SD's RUN bit is set. */
-    uint32_t u32SDCTL = HDA_STREAM_REG(pThis, CTL, pStream->u8SD);
-    bool fIsRunning   = RT_BOOL(u32SDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+    bool fIsRunning = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
     if (fIsRunning)
     {
-        LogFunc(("[SD%RU8]: Warning: Cannot write to register 0x%x (0x%x) when RUN bit is set (%R[sdctl])\n",
-                 pStream->u8SD, iReg, u32Value, u32SDCTL));
-#  ifdef DEBUG_andy
-        AssertFailed();
-#  endif
-        return VERR_ACCESS_DENIED;
+#ifdef VBOX_STRICT
+        AssertMsgFailed(("[SD%RU8]: Cannot write to register 0x%x (0x%x) when RUN bit is set\n",
+                         HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), iReg, u32Value));
+#endif
+        return false;
     }
-# endif
-
-    return RTCritSectEnter(&pStream->State.CritSect);
-}
-
-DECLINLINE(void) hdaRegWriteSDUnlock(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
 
-    int rc2 = RTCritSectLeave(&pStream->State.CritSect);
-    AssertRC(rc2);
+    return true;
 }
-#endif /* IN_RING3 */
 
 static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
+    int rc = VINF_SUCCESS;
     /* regarding 3.4.3 we should mark IRS as busy in case CORB is active */
     if (   HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP)
         || HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA))
-    {
         HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB);  /* busy */
-    }
 
-    return hdaRegReadU32(pThis, iReg, pu32Value);
+    rc = hdaRegReadU32(pThis, iReg, pu32Value);
+    return rc;
 }
 
 static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF_PV(iReg);
+    RT_NOREF(iReg);
+    int rc = VINF_SUCCESS;
 
     /*
      * If the guest set the ICB bit of IRS register, HDA should process the verb in IC register,
@@ -3046,51 +2351,56 @@ static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
         && !HDA_REG_FLAG_VALUE(pThis, IRS, ICB))
     {
 #ifdef IN_RING3
-        uint32_t uCmd = HDA_REG(pThis, IC);
-
+        PFNHDACODECVERBPROCESSOR    pfn = NULL;
+        uint64_t                    resp;
+        uint32_t cmd = HDA_REG(pThis, IC);
         if (HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP))
         {
             /*
-             * 3.4.3: Defines behavior of immediate Command status register.
+             * 3.4.3 defines behavior of immediate Command status register.
              */
-            LogRel(("HDA: Guest attempted process immediate verb (%x) with active CORB\n", uCmd));
-            return VINF_SUCCESS;
+            LogRel(("guest attempted process immediate verb (%x) with active CORB\n", cmd));
+            return rc;
         }
-
         HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB);  /* busy */
+        LogFunc(("IC:%x\n", cmd));
 
-        uint64_t uResp;
-        int rc2 = pThis->pCodec->pfnLookup(pThis->pCodec,
-                                           HDA_CODEC_CMD(uCmd, 0 /* LUN */), &uResp);
-        if (RT_FAILURE(rc2))
-            LogFunc(("Codec lookup failed with rc2=%Rrc\n", rc2));
+        rc = pThis->pCodec->pfnLookup(pThis->pCodec,
+                                      HDA_CODEC_CMD(cmd, 0 /* LUN */),
+                                      &pfn);
+        if (RT_FAILURE(rc))
+            AssertRCReturn(rc, rc);
+        rc = pfn(pThis->pCodec,
+                 HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
+        if (RT_FAILURE(rc))
+            AssertRCReturn(rc, rc);
 
-        HDA_REG(pThis, IR)   = (uint32_t)uResp; /** @todo r=andy Do we need a 64-bit response? */
-        HDA_REG(pThis, IRS)  = HDA_REG_FIELD_FLAG_MASK(IRS, IRV);  /* result is ready  */
+        HDA_REG(pThis, IR) = (uint32_t)resp;
+        LogFunc(("IR:%x\n", HDA_REG(pThis, IR)));
+        HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, IRV);  /* result is ready  */
         HDA_REG(pThis, IRS) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy is clear */
-        return VINF_SUCCESS;
-#else  /* !IN_RING3 */
-        return VINF_IOM_R3_MMIO_WRITE;
-#endif /* !IN_RING3 */
+#else /* !IN_RING3 */
+        rc = VINF_IOM_R3_MMIO_WRITE;
+#endif
+        return rc;
     }
-
     /*
      * Once the guest read the response, it should clean the IRV bit of the IRS register.
      */
     if (   u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, IRV)
         && HDA_REG_FLAG_VALUE(pThis, IRS, IRV))
         HDA_REG(pThis, IRS) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, IRV);
-    return VINF_SUCCESS;
+    return rc;
 }
 
 static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     if (u32Value & HDA_REG_FIELD_FLAG_MASK(RIRBWP, RST))
+    {
         HDA_REG(pThis, RIRBWP) = 0;
-
-    /* The remaining bits are O, see 6.2.22. */
+    }
+    /* The remaining bits are O, see 6.2.22 */
     return VINF_SUCCESS;
 }
 
@@ -3125,8 +2435,8 @@ static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
             pThis->u64DPBase |= pThis->au32Regs[iRegMem];
 
             /* Also make sure to handle the DMA position enable bit. */
-            pThis->fDMAPosition = RT_BOOL(pThis->u64DPBase & RT_BIT_64(0));
-            LogRel2(("HDA: %s DMA position buffer\n", pThis->fDMAPosition ? "Enabled" : "Disabled"));
+            pThis->fDMAPosition = pThis->au32Regs[iRegMem] & RT_BIT_32(0);
+            LogRel(("HDA: %s DMA position buffer\n", pThis->fDMAPosition ? "Enabled" : "Disabled"));
             break;
         }
         case HDA_REG_DPUBASE:
@@ -3145,8 +2455,7 @@ static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 
 static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    RT_NOREF_PV(iReg);
-
+    RT_NOREF(iReg);
     uint8_t v = HDA_REG(pThis, RIRBSTS);
     HDA_REG(pThis, RIRBSTS) &= ~(v & u32Value);
 
@@ -3154,7 +2463,7 @@ static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 }
 
 #ifdef IN_RING3
-#ifdef LOG_ENABLED
+# ifdef LOG_ENABLED
 static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
 {
     LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE));
@@ -3193,7 +2502,7 @@ static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
         LogFlowFunc(("\t#%03d DMA @ 0x%x\n", i , uDMACnt));
     }
 }
-#endif
+# endif
 
 /**
  * Fetches a Bundle Descriptor List Entry (BDLE) from the DMA engine.
@@ -3208,12 +2517,6 @@ static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, ui
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pBDLE,   VERR_INVALID_POINTER);
     AssertReturn(u64BaseDMA, VERR_INVALID_PARAMETER);
-
-    if (!u64BaseDMA)
-    {
-        LogRel2(("HDA: Unable to fetch BDLE #%RU16 - no base DMA address set (yet)\n", u16Entry));
-        return VERR_NOT_FOUND;
-    }
     /** @todo Compare u16Entry with LVI. */
 
     uint8_t uBundleEntry[16]; /** @todo Define a BDLE length. */
@@ -3230,7 +2533,7 @@ static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, ui
     if (pBDLE->u32BufSize < sizeof(uint16_t)) /* Must be at least one word. */
         return VERR_INVALID_STATE;
 
-    pBDLE->fIntOnCompletion  = (*(uint32_t *)&uBundleEntry[12]) & RT_BIT(0);
+    pBDLE->fIntOnCompletion  = (*(uint32_t *)&uBundleEntry[12]) & 0x1;
 
     return VINF_SUCCESS;
 }
@@ -3241,27 +2544,24 @@ static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, ui
  *
  * @return Number of bytes for the DMA engine to process.
  */
-DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbMax)
+DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax)
 {
-    AssertPtrReturn(pThis,   0);
-    AssertPtrReturn(pStream, 0);
+    AssertPtrReturn(pThis, 0);
+    AssertPtrReturn(pStrmSt, 0);
 
     if (!cbMax)
         return 0;
 
-    PHDABDLE pBDLE = &pStream->State.BDLE;
+    PHDABDLE pBDLE = &pStrmSt->State.BDLE;
 
-    uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-    Assert(u32LPIB <= pStream->u32CBL);
-
-    uint32_t cbFree = pStream->u32CBL - u32LPIB;
+    uint32_t cbFree = pStrmSt->u32CBL - HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
     if (cbFree)
     {
         /* Limit to the available free space of the current BDLE. */
         cbFree = RT_MIN(cbFree, pBDLE->u32BufSize - pBDLE->State.u32BufOff);
 
         /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
-        cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
+        cbFree = RT_MIN(cbFree, pStrmSt->u16FIFOS);
 
         /* Make sure we only transfer as many bytes as requested. */
         cbFree = RT_MIN(cbFree, cbMax);
@@ -3279,8 +2579,8 @@ DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrea
         }
     }
 
-    LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, FIFOS=%RU16, cbFree=%RU32, %R[bdle]\n", pStream->u8SD,
-                 pStream->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u16FIFOS, cbFree, pBDLE));
+    LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, cbFree=%RU32, %R[bdle]\n", pStrmSt->u8Strm,
+                 pStrmSt->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), cbFree, pBDLE));
     return cbFree;
 }
 
@@ -3318,153 +2618,48 @@ DECLINLINE(void) hdaBDLEUpdate(PHDABDLE pBDLE, uint32_t cbData, uint32_t cbProce
     LogFlowFunc(("cbData=%RU32, cbProcessed=%RU32, %R[bdle]\n", cbData, cbProcessed, pBDLE));
 }
 
-#ifdef IN_RING3
-/**
- * Initializes a stream mapping structure according to the given stream configuration.
- *
- * @return  IPRT status code.
- * @param   pMapping            Pointer to mapping to initialize.
- * @param   pCfg                Pointer to stream configuration to use.
- */
-static int hdaStreamMapInit(PHDASTREAMMAPPING pMapping, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pMapping, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,     VERR_INVALID_POINTER);
-
-    AssertReturn(pCfg->cChannels, VERR_INVALID_PARAMETER);
-
-    hdaStreamMapReset(pMapping);
-
-    pMapping->paChannels = (PPDMAUDIOSTREAMCHANNEL)RTMemAlloc(sizeof(PDMAUDIOSTREAMCHANNEL) * pCfg->cChannels);
-    if (!pMapping->paChannels)
-        return VERR_NO_MEMORY;
-
-    PDMAUDIOPCMPROPS Props;
-    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &Props);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    Assert(RT_IS_POWER_OF_TWO(Props.cBits));
-
-    /** @todo We assume all channels in a stream have the same format. */
-    PPDMAUDIOSTREAMCHANNEL pChan = pMapping->paChannels;
-    for (uint8_t i = 0; i < pCfg->cChannels; i++)
-    {
-        pChan->uChannel = i;
-        pChan->cbStep   = (Props.cBits / 2);
-        pChan->cbFrame  = pChan->cbStep * pCfg->cChannels;
-        pChan->cbFirst  = i * pChan->cbStep;
-        pChan->cbOff    = pChan->cbFirst;
-
-        int rc2 = hdaStreamChannelDataInit(&pChan->Data, PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE);
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-
-        if (RT_FAILURE(rc))
-            break;
-
-        pChan++;
-    }
-
-    if (   RT_SUCCESS(rc)
-        /* Create circular buffer if not created yet. */
-        && !pMapping->pCircBuf)
-    {
-        rc = RTCircBufCreate(&pMapping->pCircBuf, _4K); /** @todo Make size configurable? */
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        pMapping->cChannels = pCfg->cChannels;
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
-        pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_INTERLEAVED;
-#else
-        pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
-#endif
-    }
-
-    return rc;
-}
-
-/**
- * Destroys a given stream mapping.
- *
- * @param   pMapping            Pointer to mapping to destroy.
- */
-static void hdaStreamMapDestroy(PHDASTREAMMAPPING pMapping)
-{
-    hdaStreamMapReset(pMapping);
-
-    if (pMapping->pCircBuf)
-    {
-        RTCircBufDestroy(pMapping->pCircBuf);
-        pMapping->pCircBuf = NULL;
-    }
-}
-
-/**
- * Resets a given stream mapping.
- *
- * @param   pMapping            Pointer to mapping to reset.
- */
-static void hdaStreamMapReset(PHDASTREAMMAPPING pMapping)
-{
-    AssertPtrReturnVoid(pMapping);
-
-    pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_UNKNOWN;
-
-    if (pMapping->cChannels)
-    {
-        for (uint8_t i = 0; i < pMapping->cChannels; i++)
-            hdaStreamChannelDataDestroy(&pMapping->paChannels[i].Data);
-
-        AssertPtr(pMapping->paChannels);
-        RTMemFree(pMapping->paChannels);
-        pMapping->paChannels = NULL;
-
-        pMapping->cChannels = 0;
-    }
-}
-#endif /* IN_RING3 */
-
-DECLINLINE(bool) hdaStreamNeedsNextBDLE(PHDASTATE pThis, PHDASTREAM pStream)
+DECLINLINE(bool) hdaStreamNeedsNextBDLE(PHDASTATE pThis, PHDASTREAM pStrmSt)
 {
     AssertPtrReturn(pThis,   false);
-    AssertPtrReturn(pStream, false);
+    AssertPtrReturn(pStrmSt, false);
 
-    PHDABDLE pBDLE   = &pStream->State.BDLE;
-    uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
+    PHDABDLE pBDLE   = &pStrmSt->State.BDLE;
+    uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
 
     /* Did we reach the CBL (Cyclic Buffer List) limit? */
-    bool fCBLLimitReached = u32LPIB >= pStream->u32CBL;
+    bool fCBLLimitReached = u32LPIB >= pStrmSt->u32CBL;
 
     /* Do we need to use the next BDLE entry? Either because we reached
      * the CBL limit or our internal DMA buffer is full. */
     bool fNeedsNextBDLE   = (   fCBLLimitReached
                              || (pBDLE->State.u32BufOff >= pBDLE->u32BufSize));
 
-    Assert(u32LPIB                <= pStream->u32CBL);
+    Assert(u32LPIB                <= pStrmSt->u32CBL);
     Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
 
     LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32, fCBLLimitReached=%RTbool, fNeedsNextBDLE=%RTbool, %R[bdle]\n",
-                 pStream->u8SD, u32LPIB, pStream->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
+                 pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
+
+    if (fCBLLimitReached)
+    {
+        /* Reset LPIB register. */
+        u32LPIB -= RT_MIN(u32LPIB, pStrmSt->u32CBL);
+        hdaStreamUpdateLPIB(pThis, pStrmSt, u32LPIB);
+    }
 
     return fNeedsNextBDLE;
 }
 
-DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbInc)
+DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbInc)
 {
     AssertPtrReturnVoid(pThis);
-    AssertPtrReturnVoid(pStream);
+    AssertPtrReturnVoid(pStrmSt);
 
-    LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStream->u8SD, cbInc));
+    LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStrmSt->u8Strm, cbInc));
 
-    //Assert(cbInc <= pStream->u16FIFOS);
+    Assert(cbInc <= pStrmSt->u16FIFOS);
 
-    if (!cbInc) /* Nothing to do? Bail out early. */
-        return;
-
-    PHDABDLE pBDLE = &pStream->State.BDLE;
+    PHDABDLE pBDLE = &pStrmSt->State.BDLE;
 
     /*
      * If we're below the FIFO watermark (SDFIFOW), it's expected that HDA
@@ -3473,40 +2668,33 @@ DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStream, ui
      */
     if (pBDLE->State.cbBelowFIFOW == 0) /* Did we hit (or exceed) the watermark? */
     {
-        uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-
-        AssertMsg(((u32LPIB + cbInc) <= pStream->u32CBL),
-                  ("[SD%RU8] Increment (%RU32) exceeds CBL (%RU32): LPIB (%RU32)\n",
-                   pStream->u8SD, cbInc, pStream->u32CBL, u32LPIB));
-
-        u32LPIB = RT_MIN(u32LPIB + cbInc, pStream->u32CBL);
+        const uint32_t u32LPIB = RT_MIN(HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
+                                        pStrmSt->u32CBL);
 
         LogFlowFunc(("[SD%RU8]: LPIB: %RU32 -> %RU32, CBL=%RU32\n",
-                     pStream->u8SD,
-                     HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) + cbInc,
-                     pStream->u32CBL));
+                     pStrmSt->u8Strm,
+                     HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
+                     pStrmSt->u32CBL));
 
-        hdaStreamUpdateLPIB(pThis, pStream, u32LPIB);
+        hdaStreamUpdateLPIB(pThis, pStrmSt, u32LPIB);
     }
 }
 
-static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStream, bool *pfInterrupt)
+static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStrmSt)
 {
     AssertPtrReturn(pThis,   true);
-    AssertPtrReturn(pStream, true);
+    AssertPtrReturn(pStrmSt, true);
 
-    bool fInterrupt  = false;
     bool fIsComplete = false;
 
-    PHDABDLE       pBDLE   = &pStream->State.BDLE;
-#ifdef LOG_ENABLED
-    const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-#endif
+    PHDABDLE       pBDLE   = &pStrmSt->State.BDLE;
+    const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
 
-    /* Check if the current BDLE entry is complete (full). */
-    if (pBDLE->State.u32BufOff >= pBDLE->u32BufSize)
+    if (   pBDLE->State.u32BufOff >= pBDLE->u32BufSize
+        || u32LPIB                >= pStrmSt->u32CBL)
     {
         Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
+        Assert(u32LPIB                <= pStrmSt->u32CBL);
 
         if (/* IOC (Interrupt On Completion) bit set? */
                pBDLE->fIntOnCompletion
@@ -3514,24 +2702,31 @@ static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStream, boo
             && pBDLE->State.cbBelowFIFOW == 0
            )
         {
-            LogFlowFunc(("[SD%RU8]: %R[bdle] => COMPLETE\n",  pStream->u8SD, pBDLE));
+            /**
+             * Set the BCIS (Buffer Completion Interrupt Status) flag as the
+             * last byte of data for the current descriptor has been fetched
+             * from memory and put into the DMA FIFO.
+             *
+             ** @todo More carefully investigate BCIS flag.
+             *
+             * Speech synthesis works fine on Mac Guest if this bit isn't set
+             * but in general sound quality gets worse.
+             */
+            HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
 
             /*
              * If the ICE (IOCE, "Interrupt On Completion Enable") bit of the SDCTL register is set
              * we need to generate an interrupt.
              */
-            if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
-                fInterrupt = true;
+            if (HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
+                hdaProcessInterrupt(pThis);
         }
 
         fIsComplete = true;
     }
 
-    if (pfInterrupt)
-        *pfInterrupt = fInterrupt;
-
-    LogFlowFunc(("[SD%RU8]: u32LPIB=%RU32, CBL=%RU32, fIsComplete=%RTbool, fInterrupt=%RTbool, %R[bdle]\n",
-                 pStream->u8SD, u32LPIB, pStream->u32CBL, fIsComplete, fInterrupt, pBDLE));
+    LogFlowFunc(("[SD%RU8]: u32LPIB=%RU32, CBL=%RU32, %R[bdle] => %s\n",
+                 pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE"));
 
     return fIsComplete;
 }
@@ -3541,210 +2736,160 @@ static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStream, boo
  * Note: This function writes to the DMA buffer immediately,
  *       but "reports bytes" when all conditions are met (FIFOW).
  */
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
+static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, PAUDMIXSINK pSink, uint32_t cbMax, uint32_t *pcbRead)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSink,   VERR_INVALID_POINTER);
     /* pcbRead is optional. */
 
+    PHDABDLE pBDLE = &pStrmSt->State.BDLE;
+
     int rc;
     uint32_t cbRead = 0;
+    uint32_t cbBuf  = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
 
-    do
-    {
-        PHDABDLE pBDLE = &pStream->State.BDLE;
+    LogFlowFunc(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE));
 
-        if (!cbToRead)
+    if (!cbBuf)
+    {
+        /* Nothing to write, bail out. */
+        rc = VINF_EOF;
+    }
+    else
+    {
+        rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
+        if (RT_SUCCESS(rc))
         {
-            rc = VINF_EOF;
-            break;
-        }
+            if (!cbRead)
+            {
+                rc = VINF_EOF;
+            }
+            else
+            {
+                /* Sanity checks. */
+                Assert(cbRead <= pStrmSt->u16FIFOS);
+                Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
 
-        AssertPtr(pStream->pMixSink);
-        AssertPtr(pStream->pMixSink->pMixSink);
-        rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToRead, &cbRead);
-        if (RT_FAILURE(rc))
-            break;
-
-        if (!cbRead)
-        {
-            rc = VINF_EOF;
-            break;
-        }
-
-        /* Sanity checks. */
-        Assert(cbRead <= cbToRead);
-        Assert(cbRead <= sizeof(pBDLE->State.au8FIFO));
-        Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
-
-        /*
-         * Write to the BDLE's DMA buffer.
-         */
-        rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
-                                   pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
-                                   pBDLE->State.au8FIFO, cbRead);
-        AssertRC(rc);
+                /*
+                 * Write to the BDLE's DMA buffer.
+                 */
+                rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
+                                           pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
+                                           pBDLE->State.au8FIFO, cbRead);
+                AssertRC(rc);
 
-        if (pBDLE->State.cbBelowFIFOW + cbRead > hdaStreamGetFIFOW(pThis, pStream))
-        {
-            Assert(pBDLE->State.u32BufOff + cbRead <= pBDLE->u32BufSize);
-            pBDLE->State.u32BufOff    += cbRead;
-            pBDLE->State.cbBelowFIFOW  = 0;
-            //hdaBackendReadTransferReported(pBDLE, cbDMAData, cbRead, &cbRead, pcbAvail);
-        }
-        else
-        {
-            Assert(pBDLE->State.u32BufOff + cbRead <= pBDLE->u32BufSize);
-            pBDLE->State.u32BufOff    += cbRead;
-            pBDLE->State.cbBelowFIFOW += cbRead;
-            Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStream));
-            //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbRead, pcbAvail);
+                if (pBDLE->State.cbBelowFIFOW + cbRead > hdaStreamGetFIFOW(pThis, pStrmSt))
+                {
+                    pBDLE->State.u32BufOff    += cbRead;
+                    pBDLE->State.cbBelowFIFOW  = 0;
+                    //hdaBackendReadTransferReported(pBDLE, cbDMAData, cbRead, &cbRead, pcbAvail);
+                }
+                else
+                {
+                    pBDLE->State.u32BufOff    += cbRead;
+                    pBDLE->State.cbBelowFIFOW += cbRead;
+                    Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
+                    //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbRead, pcbAvail);
 
-            rc = VERR_NO_DATA;
+                    rc = VERR_NO_DATA;
+                }
+            }
         }
-
-    } while (0);
+    }
 
     if (RT_SUCCESS(rc))
     {
         if (pcbRead)
             *pcbRead = cbRead;
     }
-
-    if (RT_FAILURE(rc))
+    else
         LogFlowFunc(("Failed with %Rrc\n", rc));
 
     return rc;
 }
 
-static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
+static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
 {
     AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
     /* pcbWritten is optional. */
 
-    PHDABDLE pBDLE = &pStream->State.BDLE;
+    PHDABDLE pBDLE = &pStrmSt->State.BDLE;
 
     uint32_t cbWritten = 0;
+    uint32_t cbData    = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
+
+    LogFlowFunc(("cbData=%RU32, %R[bdle]\n", cbData, pBDLE));
 
     /*
      * Copy from DMA to the corresponding stream buffer (if there are any bytes from the
      * previous unreported transfer we write at offset 'pBDLE->State.cbUnderFifoW').
      */
     int rc;
-    if (!cbToWrite)
+    if (!cbData)
     {
         rc = VINF_EOF;
     }
     else
     {
-        void    *pvBuf = pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW;
-        Assert(cbToWrite >= pBDLE->State.cbBelowFIFOW);
-        uint32_t cbBuf = cbToWrite - pBDLE->State.cbBelowFIFOW;
-
         /*
          * Read from the current BDLE's DMA buffer.
          */
         rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
                                pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
-                               pvBuf, cbBuf);
+                               pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW, cbData);
         AssertRC(rc);
 
-#ifdef HDA_DEBUG_DUMP_PCM_DATA
-        RTFILE fh;
-        RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio-hda.pcm",
-                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-        RTFileWrite(fh, pvBuf, cbBuf, NULL);
-        RTFileClose(fh);
-#endif
-
 #ifdef VBOX_WITH_STATISTICS
-        STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBuf);
+        STAM_COUNTER_ADD(&pThis->StatBytesRead, cbData);
 #endif
         /*
          * Write to audio backend. We should ensure that we have enough bytes to copy to the backend.
          */
-        if (cbBuf >= hdaStreamGetFIFOW(pThis, pStream))
+        uint32_t cbToWrite = cbData + pBDLE->State.cbBelowFIFOW;
+        if (cbToWrite >= hdaStreamGetFIFOW(pThis, pStrmSt))
         {
-#if defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND)
-            PHDASTREAMMAPPING pMapping            = &pStream->State.Mapping;
-#endif
-
-            /** @todo Which channel is which? */
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
-            PPDMAUDIOSTREAMCHANNEL pChanFront     = &pMapping->paChannels[0];
-#endif
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            PPDMAUDIOSTREAMCHANNEL pChanCenterLFE = &pMapping->paChannels[2]; /** @todo FIX! */
-            PPDMAUDIOSTREAMCHANNEL pChanRear      = &pMapping->paChannels[4]; /** @todo FIX! */
-#endif
+            uint32_t cbWrittenToStream;
             int rc2;
 
-            void  *pvDataFront = NULL;
-            size_t cbDataFront;
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
-            rc2 = hdaStreamChannelExtract(pChanFront, pvBuf, cbBuf);
-            AssertRC(rc2);
-
-            rc2 = hdaStreamChannelAcquireData(&pChanFront->Data, pvDataFront, &cbDataFront);
-            AssertRC(rc2);
-#else
-            /* Use stuff in the whole FIFO to use for the channel data. */
-            pvDataFront = pvBuf;
-            cbDataFront = cbBuf;
-#endif
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            void  *pvDataCenterLFE;
-            size_t cbDataCenterLFE;
-            rc2 = hdaStreamChannelExtract(pChanCenterLFE, pvBuf, cbBuf);
-            AssertRC(rc2);
-
-            rc2 = hdaStreamChannelAcquireData(&pChanCenterLFE->Data, pvDataCenterLFE, &cbDataCenterLFE);
-            AssertRC(rc2);
-
-            void  *pvDataRear;
-            size_t cbDataRear;
-            rc2 = hdaStreamChannelExtract(pChanRear, pvBuf, cbBuf);
-            AssertRC(rc2);
-
-            rc2 = hdaStreamChannelAcquireData(&pChanRear->Data, pvDataRear, &cbDataRear);
-            AssertRC(rc2);
-#endif
-            /*
-             * Write data to according mixer sinks.
-             */
-            rc2 = AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, pvDataFront,     (uint32_t)cbDataFront,
-                                      NULL /* pcbWritten */);
-            AssertRC(rc2);
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            rc2 = AudioMixerSinkWrite(pThis->SinkCenterLFE,      AUDMIXOP_COPY, pvDataCenterLFE, cbDataCenterLFE,
-                                      NULL /* pcbWritten */);
-            AssertRC(rc2);
-            rc2 = AudioMixerSinkWrite(pThis->SinkRear,           AUDMIXOP_COPY, pvDataRear,      cbDataRear,
-                                      NULL /* pcbWritten */);
-            AssertRC(rc2);
-#endif
+            PHDADRIVER pDrv;
+            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+            {
+                if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+                {
+                    rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+                                                     pBDLE->State.au8FIFO, cbToWrite, &cbWrittenToStream);
+                    if (RT_SUCCESS(rc2))
+                    {
+                        if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
+                            LogFlowFunc(("\tLUN#%RU8: Warning: Only written %RU32 / %RU32 bytes, expect lags\n",
+                                         pDrv->uLUN, cbWrittenToStream, cbToWrite));
+                    }
+                }
+                else /* Stream disabled, not fatal. */
+                {
+                    cbWrittenToStream = 0;
+                    rc2 = VERR_NOT_AVAILABLE;
+                    /* Keep going. */
+                }
 
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
-            hdaStreamChannelReleaseData(&pChanFront->Data);
-#endif
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            hdaStreamChannelReleaseData(&pChanCenterLFE->Data);
-            hdaStreamChannelReleaseData(&pChanRear->Data);
-#endif
+                LogFlowFunc(("\tLUN#%RU8: cbToWrite=%RU32, cbWrittenToStream=%RU32, rc=%Rrc\n",
+                             pDrv->uLUN, cbToWrite, cbWrittenToStream, rc2));
+            }
 
             /* Always report all data as being written;
              * backends who were not able to catch up have to deal with it themselves. */
             cbWritten = cbToWrite;
 
-            hdaBDLEUpdate(pBDLE, cbToWrite, cbWritten);
+            hdaBDLEUpdate(pBDLE, cbData, cbWritten);
         }
         else
         {
-            Assert(pBDLE->State.u32BufOff + cbWritten <= pBDLE->u32BufSize);
-            pBDLE->State.u32BufOff    += cbWritten;
+            pBDLE->State.u32BufOff += cbWritten;
             pBDLE->State.cbBelowFIFOW += cbWritten;
-            Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStream));
+            Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
 
             /* Not enough bytes to be processed and reported, we'll try our luck next time around. */
             //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbAvail, NULL);
@@ -3752,7 +2897,7 @@ static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite
         }
     }
 
-    //Assert(cbWritten <= pStream->u16FIFOS);
+    Assert(cbWritten <= pStrmSt->u16FIFOS);
 
     if (RT_SUCCESS(rc))
     {
@@ -3760,9 +2905,7 @@ static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite
             *pcbWritten = cbWritten;
     }
 
-    if (RT_FAILURE(rc))
-        LogFlowFunc(("Failed with %Rrc\n", rc));
-
+    LogFunc(("Returning cbWritten=%RU32, rc=%Rrc\n", cbWritten, rc));
     return rc;
 }
 
@@ -3776,357 +2919,129 @@ static DECLCALLBACK(int) hdaCodecReset(PHDACODEC pCodec)
     return VINF_SUCCESS;
 }
 
-/**
- * Retrieves a corresponding sink for a given mixer control.
- * Returns NULL if no sink is found.
- *
- * @return  PHDAMIXERSINK
- * @param   pThis               HDA state.
- * @param   enmMixerCtl         Mixer control to get the corresponding sink for.
- */
-static PHDAMIXERSINK hdaMixerControlToSink(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
+
+static DECLCALLBACK(void) hdaCloseIn(PHDASTATE pThis, PDMAUDIORECSOURCE enmRecSource)
 {
-    PHDAMIXERSINK pSink;
+    NOREF(pThis);
+    NOREF(enmRecSource);
+    LogFlowFuncEnter();
+}
 
-    switch (enmMixerCtl)
+static DECLCALLBACK(void) hdaCloseOut(PHDASTATE pThis)
+{
+    NOREF(pThis);
+    LogFlowFuncEnter();
+}
+
+static DECLCALLBACK(int) hdaOpenIn(PHDASTATE pThis,
+                                   const char *pszName, PDMAUDIORECSOURCE enmRecSource,
+                                   PPDMAUDIOSTREAMCFG pCfg)
+{
+    PAUDMIXSINK pSink;
+
+    switch (enmRecSource)
     {
-        case PDMAUDIOMIXERCTL_VOLUME_MASTER:
-            /* Fall through is intentional. */
-        case PDMAUDIOMIXERCTL_FRONT:
-            pSink = &pThis->SinkFront;
-            break;
-#ifdef VBOX_WITH_HDA_51_SURROUND
-        case PDMAUDIOMIXERCTL_CENTER_LFE:
-            pSink = &pThis->SinkCenterLFE;
-            break;
-        case PDMAUDIOMIXERCTL_REAR:
-            pSink = &pThis->SinkRear;
-            break;
-#endif
-        case PDMAUDIOMIXERCTL_LINE_IN:
-            pSink = &pThis->SinkLineIn;
+# ifdef VBOX_WITH_HDA_MIC_IN
+        case PDMAUDIORECSOURCE_MIC:
+            pSink = pThis->pSinkMicIn;
             break;
-#ifdef VBOX_WITH_HDA_MIC_IN
-        case PDMAUDIOMIXERCTL_MIC_IN:
-            pSink = &pThis->SinkMicIn;
+# endif
+        case PDMAUDIORECSOURCE_LINE_IN:
+            pSink = pThis->pSinkLineIn;
             break;
-#endif
         default:
-            pSink = NULL;
-            AssertMsgFailed(("Unhandled mixer control\n"));
-            break;
+            AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
+            return VERR_NOT_SUPPORTED;
     }
 
-    return pSink;
-}
-
-static DECLCALLBACK(int) hdaMixerAddStream(PHDASTATE pThis, PHDAMIXERSINK pSink, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
-
-    LogFunc(("Sink=%s, Stream=%s\n", pSink->pMixSink->pszName, pCfg->szName));
-
-    /* Update the sink's format. */
-    PDMAUDIOPCMPROPS PCMProps;
-    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
-    if (RT_SUCCESS(rc))
-        rc = AudioMixerSinkSetFormat(pSink->pMixSink, &PCMProps);
-
-    if (RT_FAILURE(rc))
-        return rc;
+    int rc = VINF_SUCCESS;
+    char *pszDesc;
 
     PHDADRIVER pDrv;
     RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     {
-        int rc2 = VINF_SUCCESS;
-        PHDAMIXERSTREAM pStream = NULL;
-
-        PPDMAUDIOSTREAMCFG pStreamCfg = (PPDMAUDIOSTREAMCFG)RTMemDup(pCfg, sizeof(PDMAUDIOSTREAMCFG));
-        if (!pStreamCfg)
+        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
         {
             rc = VERR_NO_MEMORY;
             break;
         }
 
-        /* Include the driver's LUN in the stream name for easier identification. */
-        RTStrPrintf(pStreamCfg->szName, RT_ELEMENTS(pStreamCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pCfg->szName);
-
-        if (pStreamCfg->enmDir == PDMAUDIODIR_IN)
-        {
-            LogFunc(("enmRecSource=%d\n", pStreamCfg->DestSource.Source));
-
-            switch (pStreamCfg->DestSource.Source)
-            {
-                case PDMAUDIORECSOURCE_LINE:
-                    pStream = &pDrv->LineIn;
-                    break;
-#ifdef VBOX_WITH_HDA_MIC_IN
-                case PDMAUDIORECSOURCE_MIC:
-                    pStream = &pDrv->MicIn;
-                    break;
-#endif
-                default:
-                    rc2 = VERR_NOT_SUPPORTED;
-                    break;
-            }
-        }
-        else if (pStreamCfg->enmDir == PDMAUDIODIR_OUT)
-        {
-            LogFunc(("enmPlaybackDest=%d\n", pStreamCfg->DestSource.Dest));
-
-            switch (pStreamCfg->DestSource.Dest)
-            {
-                case PDMAUDIOPLAYBACKDEST_FRONT:
-                    pStream = &pDrv->Front;
-                    break;
-#ifdef VBOX_WITH_HDA_51_SURROUND
-                case PDMAUDIOPLAYBACKDEST_CENTER_LFE:
-                    pStream = &pDrv->CenterLFE;
-                    break;
-                case PDMAUDIOPLAYBACKDEST_REAR:
-                    pStream = &pDrv->Rear;
-                    break;
-#endif
-                default:
-                    rc2 = VERR_NOT_SUPPORTED;
-                    break;
-            }
-        }
-        else
-            rc2 = VERR_NOT_SUPPORTED;
-
-        if (RT_SUCCESS(rc2))
-        {
-            AssertPtr(pStream);
-
-            AudioMixerSinkRemoveStream(pSink->pMixSink, pStream->pMixStrm);
-
-            AudioMixerStreamDestroy(pStream->pMixStrm);
-            pStream->pMixStrm = NULL;
-
-            PAUDMIXSTREAM pMixStrm;
-            rc2 = AudioMixerSinkCreateStream(pSink->pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm);
-            if (RT_SUCCESS(rc2))
-            {
-                rc2 = AudioMixerSinkAddStream(pSink->pMixSink, pMixStrm);
-                LogFlowFunc(("LUN#%RU8: Added \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName , rc2));
-            }
-
-            if (RT_SUCCESS(rc2))
-                pStream->pMixStrm = pMixStrm;
-        }
-
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-
-        if (pStreamCfg)
+        rc = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pDrv->LineIn.pStrmIn);
+        LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+        if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
         {
-            RTMemFree(pStreamCfg);
-            pStreamCfg = NULL;
+            AudioMixerRemoveStream(pSink, pDrv->LineIn.phStrmIn);
+            rc = AudioMixerAddStreamIn(pSink,
+                                       pDrv->pConnector, pDrv->LineIn.pStrmIn,
+                                       0 /* uFlags */, &pDrv->LineIn.phStrmIn);
         }
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
 
-/**
- * Adds a new audio stream to a specific mixer control.
- * Depending on the mixer control the stream then gets assigned to one of the internal
- * mixer sinks, which in turn then handle the mixing of all connected streams to that sink.
- *
- * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   enmMixerCtl         Mixer control to assign new stream to.
- * @param   pCfg                Stream configuration for the new stream.
- */
-static DECLCALLBACK(int) hdaMixerAddStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
-
-    int rc;
-
-    PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
-    if (pSink)
-    {
-        rc = hdaMixerAddStream(pThis, pSink, pCfg);
-
-        AssertPtr(pSink->pMixSink);
-        LogFlowFunc(("Sink=%s, enmMixerCtl=%d\n", pSink->pMixSink->pszName, enmMixerCtl));
+        RTStrFree(pszDesc);
     }
-    else
-        rc = VERR_NOT_FOUND;
 
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-/**
- * Removes a specified mixer control from the HDA's mixer.
- *
- * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   enmMixerCtl         Mixer control to remove.
- */
-static DECLCALLBACK(int) hdaMixerRemoveStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
+static DECLCALLBACK(int) hdaOpenOut(PHDASTATE pThis,
+                                    const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
 {
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    int rc;
+    int rc = VINF_SUCCESS;
+    char *pszDesc;
 
-    PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
-    if (pSink)
+    PHDADRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     {
-        PHDADRIVER pDrv;
-        RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
+                         pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
         {
-            PAUDMIXSTREAM pMixStream = NULL;
-            switch (enmMixerCtl)
-            {
-                /*
-                 * Input.
-                 */
-                case PDMAUDIOMIXERCTL_LINE_IN:
-                    pMixStream = pDrv->LineIn.pMixStrm;
-                    pDrv->LineIn.pMixStrm = NULL;
-                    break;
-#ifdef VBOX_WITH_HDA_MIC_IN
-                case PDMAUDIOMIXERCTL_MIC_IN:
-                    pMixStream = pDrv->MicIn.pMixStrm;
-                    pDrv->MicIn.pMixStrm = NULL;
-                    break;
-#endif
-                /*
-                 * Output.
-                 */
-                case PDMAUDIOMIXERCTL_FRONT:
-                    pMixStream = pDrv->Front.pMixStrm;
-                    pDrv->Front.pMixStrm = NULL;
-                    break;
-#ifdef VBOX_WITH_HDA_51_SURROUND
-                case PDMAUDIOMIXERCTL_CENTER_LFE:
-                    pMixStream = pDrv->CenterLFE.pMixStrm;
-                    pDrv->CenterLFE.pMixStrm = NULL;
-                    break;
-                case PDMAUDIOMIXERCTL_REAR:
-                    pMixStream = pDrv->Rear.pMixStrm;
-                    pDrv->Rear.pMixStrm = NULL;
-                    break;
-#endif
-                default:
-                    AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
-                    break;
-            }
-
-            if (pMixStream)
-            {
-                AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
-                AudioMixerStreamDestroy(pMixStream);
-
-                pMixStream = NULL;
-            }
+            rc = VERR_NO_MEMORY;
+            break;
         }
 
-        AudioMixerSinkRemoveAllStreams(pSink->pMixSink);
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_NOT_FOUND;
-
-    LogFlowFunc(("enmMixerCtl=%d, rc=%Rrc\n", enmMixerCtl, rc));
-    return rc;
-}
-
-/**
- * Sets a SDn stream number and channel to a particular mixer control.
- *
- * @returns IPRT status code.
- * @param   pThis               HDA State.
- * @param   enmMixerCtl         Mixer control to set SD stream number and channel for.
- * @param   uSD                 SD stream number (number + 1) to set. Set to 0 for unassign.
- * @param   uChannel            Channel to set. Only valid if a valid SD stream number is specified.
- */
-static DECLCALLBACK(int) hdaMixerSetStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
-{
-    LogFlowFunc(("enmMixerCtl=%RU32, uSD=%RU8, uChannel=%RU8\n", enmMixerCtl, uSD, uChannel));
-
-    if (uSD == 0) /* Stream number 0 is reserved. */
-    {
-        LogFlowFunc(("Invalid SDn (%RU8) number for mixer control %d, ignoring\n", uSD, enmMixerCtl));
-        return VINF_SUCCESS;
-    }
-    /* uChannel is optional. */
-
-    /* SDn0 starts as 1. */
-    Assert(uSD);
-    uSD--;
-
-    int rc;
-
-    PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
-    if (pSink)
-    {
-        if (   (uSD < HDA_MAX_SDI)
-            && AudioMixerSinkGetDir(pSink->pMixSink) == AUDMIXSINKDIR_OUTPUT)
+        rc = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+        LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+        if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
         {
-            uSD += HDA_MAX_SDI;
+            AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
+            rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
+                                        pDrv->pConnector, pDrv->Out.pStrmOut,
+                                        0 /* uFlags */, &pDrv->Out.phStrmOut);
         }
 
-        LogFlowFunc(("%s: Setting to stream ID=%RU8, channel=%RU8, enmMixerCtl=%RU32\n",
-                     pSink->pMixSink->pszName, uSD, uChannel, enmMixerCtl));
-
-        Assert(uSD < HDA_MAX_STREAMS);
-
-        PHDASTREAM pStream = hdaStreamFromSD(pThis, uSD);
-        if (pStream)
-        {
-            pSink->uSD      = uSD;
-            pSink->uChannel = uChannel;
-
-            /* Make sure that the stream also has this sink set. */
-            hdaStreamAssignToSink(pStream, pSink);
-
-            rc = VINF_SUCCESS;
-        }
-        else
-        {
-            LogRel(("HDA: Guest wanted to assign invalid stream ID=%RU8 (channel %RU8) to mixer control %RU32, skipping\n",
-                    uSD, uChannel, enmMixerCtl));
-            rc = VERR_INVALID_PARAMETER;
-        }
+        RTStrFree(pszDesc);
     }
-    else
-        rc = VERR_NOT_FOUND;
 
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-/**
- * Sets the volume of a specified mixer control.
- *
- * @return  IPRT status code.
- * @param   pThis               HDA State.
- * @param   enmMixerCtl         Mixer control to set volume for.
- * @param   pVol                Pointer to volume data to set.
- */
-static DECLCALLBACK(int) hdaMixerSetVolume(PHDASTATE pThis,
-                                           PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol)
+static DECLCALLBACK(int) hdaSetVolume(PHDASTATE pThis, ENMSOUNDSOURCE enmSource,
+                                      bool fMute, uint8_t uVolLeft, uint8_t uVolRight)
 {
-    int rc;
+    int             rc = VINF_SUCCESS;
+    PDMAUDIOVOLUME  vol = { fMute, uVolLeft, uVolRight };
+    PAUDMIXSINK     pSink;
 
-    PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
-    if (pSink)
+    /* Convert the audio source to corresponding sink. */
+    switch (enmSource)
     {
-        /* Set the volume.
-         * We assume that the codec already converted it to the correct range. */
-        rc = AudioMixerSinkSetVolume(pSink->pMixSink, pVol);
+        case PO_INDEX:
+            pSink = pThis->pSinkOutput;
+            break;
+        case PI_INDEX:
+            pSink = pThis->pSinkLineIn;
+            break;
+        case MC_INDEX:
+            pSink = pThis->pSinkMicIn;
+            break;
+        default:
+            AssertFailedReturn(VERR_INVALID_PARAMETER);
+            break;
     }
-    else
-        rc = VERR_NOT_FOUND;
+
+    /* Set the volume. Codec already converted it to the correct range. */
+    AudioMixerSetSinkVolume(pSink, &vol);
 
     LogFlowFuncLeaveRC(rc);
     return rc;
@@ -4134,42 +3049,6 @@ static DECLCALLBACK(int) hdaMixerSetVolume(PHDASTATE pThis,
 
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
 
-static void hdaTimerMaybeStart(PHDASTATE pThis)
-{
-    if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
-        return;
-
-    if (!pThis->pTimer)
-        return;
-
-    LogFlowFuncEnter();
-
-    LogFlowFunc(("Starting timer\n"));
-
-    /* Set timer flag. */
-    ASMAtomicXchgBool(&pThis->fTimerActive, true);
-
-    /* Update current time timestamp. */
-    pThis->uTimerTS = TMTimerGet(pThis->pTimer);
-
-    /* Fire off timer. */
-    TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
-}
-
-static void hdaTimerMaybeStop(PHDASTATE pThis)
-{
-    if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
-        return;
-
-    if (!pThis->pTimer)
-        return;
-
-    LogFlowFunc(("Stopping timer\n"));
-
-    /* Set timer flag. */
-    ASMAtomicXchgBool(&pThis->fTimerActive, false);
-}
-
 static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
 {
     RT_NOREF(pDevIns);
@@ -4179,92 +3058,97 @@ static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pv
 
     STAM_PROFILE_START(&pThis->StatTimer, a);
 
-    uint64_t cTicksNow = TMTimerGet(pTimer);
+    uint32_t cbInMax  = 0;
+    uint32_t cbOutMin = UINT32_MAX;
 
-    LogFlowFuncEnter();
+    PHDADRIVER pDrv;
+
+    uint64_t cTicksNow     = TMTimerGet(pTimer);
+    uint64_t cTicksElapsed = cTicksNow  - pThis->uTimerTS;
+    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
 
-    /* Update current time timestamp. */
     pThis->uTimerTS = cTicksNow;
 
-    /* Flag indicating whether to kick the timer again for a
-     * new data processing round. */
-    bool fKickTimer = false;
+    /*
+     * Calculate the codec's (fixed) sampling rate.
+     */
+    AssertPtr(pThis->pCodec);
+    PDMPCMPROPS codecStrmProps;
 
-    PHDASTREAM pStreamLineIn  = hdaGetStreamFromSink(pThis, &pThis->SinkLineIn);
-#ifdef VBOX_WITH_HDA_MIC_IN
-    PHDASTREAM pStreamMicIn   = hdaGetStreamFromSink(pThis, &pThis->SinkMicIn);
-#endif
-    PHDASTREAM pStreamFront   = hdaGetStreamFromSink(pThis, &pThis->SinkFront);
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    /** @todo See note below. */
-#endif
+    int rc = DrvAudioStreamCfgToProps(&pThis->pCodec->strmCfg, &codecStrmProps);
+    AssertRC(rc);
 
-    uint32_t cbToProcess;
-    int rc = AudioMixerSinkUpdate(pThis->SinkLineIn.pMixSink);
-    if (RT_SUCCESS(rc))
-    {
-        cbToProcess = AudioMixerSinkGetReadable(pThis->SinkLineIn.pMixSink);
-        if (cbToProcess)
-        {
-            rc = hdaTransfer(pThis, pStreamLineIn, cbToProcess, NULL /* pcbProcessed */);
-            fKickTimer |= RT_SUCCESS(rc);
-        }
-    }
+    uint32_t cCodecSamplesMin  = (int)((2 * cTicksElapsed * pThis->pCodec->strmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
+    uint32_t cbCodecSamplesMin = cCodecSamplesMin << codecStrmProps.cShift;
 
-#ifdef VBOX_WITH_HDA_MIC_IN
-    rc = AudioMixerSinkUpdate(pThis->SinkMicIn.pMixSink);
-    if (RT_SUCCESS(rc))
+    /*
+     * Process all driver nodes.
+     */
+    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     {
-        cbToProcess = AudioMixerSinkGetReadable(pThis->SinkMicIn.pMixSink);
-        if (cbToProcess)
+        uint32_t cbIn = 0;
+        uint32_t cbOut = 0;
+
+        rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector, &cbIn, &cbOut, NULL /* pcSamplesLive */);
+        if (RT_SUCCESS(rc))
+            rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* pcSamplesPlayed */);
+
+        Log3Func(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
+
+        /* If we there was an error handling (available) output or there simply is no output available,
+         * then calculate the minimum data rate which must be processed by the device emulation in order
+         * to function correctly.
+         *
+         * This is not the optimal solution, but as we have to deal with this on a timer-based approach
+         * (until we have the audio callbacks) we need to have device' DMA engines running. */
+        if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
         {
-            rc = hdaTransfer(pThis, pStreamMicIn, cbToProcess, NULL /* pcbProcessed */);
-            fKickTimer |= RT_SUCCESS(rc);
+            /* Use the codec's (fixed) sampling rate. */
+            cbOut = RT_MAX(cbOut, cbCodecSamplesMin);
         }
-    }
-#endif
+        else
+        {
+            const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+            if (   RT_FAILURE(rc)
+                || !fIsActiveOut)
+            {
+                uint32_t cSamplesMin  = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+                uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
 
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    rc = AudioMixerSinkUpdate(pThis->SinkCenterLFE.pMixSink);
-    if (RT_SUCCESS(rc))
-    {
+                Log3Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
+
+                cbOut = RT_MAX(cbOut, cbSamplesMin);
+            }
+        }
 
+        cbOutMin = RT_MIN(cbOutMin, cbOut);
+        cbInMax  = RT_MAX(cbInMax, cbIn);
     }
 
-    rc = AudioMixerSinkUpdate(pThis->SinkRear.pMixSink);
-    if (RT_SUCCESS(rc))
-    {
+    Log3Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
 
-    }
-    /** @todo Check for stream interleaving and only call hdaTransfer() if required! */
+    if (cbOutMin == UINT32_MAX)
+        cbOutMin = 0;
 
     /*
-     * Only call hdaTransfer if CenterLFE and/or Rear are on different SDs,
-     * otherwise we have to use the interleaved streams support for getting the data
-     * out of the Front sink (depending on the mapping layout).
+     * Playback.
      */
-#endif
-    rc = AudioMixerSinkUpdate(pThis->SinkFront.pMixSink);
-    if (RT_SUCCESS(rc))
+    if (cbOutMin)
     {
-        cbToProcess = AudioMixerSinkGetWritable(pThis->SinkFront.pMixSink);
-        if (cbToProcess)
-        {
-            rc = hdaTransfer(pThis, pStreamFront, cbToProcess, NULL /* pcbProcessed */);
-            fKickTimer |= RT_SUCCESS(rc);
-        }
+        Assert(cbOutMin != UINT32_MAX);
+        hdaTransfer(pThis, PO_INDEX, cbOutMin /* cbToProcess */, NULL /* pcbProcessed */);
     }
 
-    if (   ASMAtomicReadBool(&pThis->fTimerActive)
-        || fKickTimer)
-    {
-        /* Kick the timer again. */
-        uint64_t cTicks = pThis->cTimerTicks;
-        /** @todo adjust cTicks down by now much cbOutMin represents. */
-        TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
-    }
+    /*
+     * Recording.
+     */
+    if (cbInMax)
+        hdaTransfer(pThis, PI_INDEX, cbInMax  /* cbToProcess */, NULL /* pcbProcessed */);
 
-    LogFlowFuncLeave();
+    /* Kick the timer again. */
+    uint64_t cTicks = pThis->cTimerTicks;
+    /** @todo adjust cTicks down by now much cbOutMin represents. */
+    TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
 
     STAM_PROFILE_STOP(&pThis->StatTimer, a);
 }
@@ -4312,201 +3196,156 @@ static DECLCALLBACK(int) hdaCallbackOutput(PDMAUDIOCALLBACKTYPE enmType, void *p
         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
         {
             uint32_t cSamplesPlayed;
-            int rc2 = pDrv->pConnector->pfnPlay(pDrv->pConnector, &cSamplesPlayed);
+            int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
             LogFlowFunc(("LUN#%RU8: cSamplesPlayed=%RU32, rc=%Rrc\n", pDrv->uLUN, cSamplesPlayed, rc2));
         }
     }
 }
 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
 
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed)
 {
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     /* pcbProcessed is optional. */
 
     if (ASMAtomicReadBool(&pThis->fInReset)) /* HDA controller in reset mode? Bail out. */
     {
-        LogFlowFunc(("HDA in reset mode, skipping\n"));
+        LogFlowFunc(("In reset mode, skipping\n"));
+
+        if (pcbProcessed)
+            *pcbProcessed = 0;
+        return VINF_SUCCESS;
+    }
+
+    PHDASTREAM pStrmSt;
+    switch (enmSrc)
+    {
+        case PI_INDEX:
+        {
+            pStrmSt = &pThis->StrmStLineIn;
+            break;
+        }
+
+#ifdef VBOX_WITH_HDA_MIC_IN
+        case MC_INDEX:
+        {
+            pStrmSt = &pThis->StrmStMicIn;
+            break;
+        }
+#endif
+        case PO_INDEX:
+        {
+            pStrmSt = &pThis->StrmStOut;
+            break;
+        }
 
-        if (pcbProcessed)
-            *pcbProcessed = 0;
-        return VINF_SUCCESS;
+        default:
+        {
+            AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
+            return VERR_NOT_SUPPORTED;
+        }
     }
 
+    int  rc       = VINF_SUCCESS;
     bool fProceed = true;
-    int rc = RTCritSectEnter(&pStream->State.CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    Log3Func(("[SD%RU8] fActive=%RTbool, cbToProcess=%RU32\n", pStream->u8SD, pStream->State.fActive, cbToProcess));
 
     /* Stop request received? */
-    if (   !pStream->State.fActive
-        || pStream->State.fDoStop)
+    if (ASMAtomicReadBool(&pStrmSt->State.fDoStop))
     {
-        pStream->State.fActive = false;
+        pStrmSt->State.fActive = false;
 
-        rc = RTSemEventSignal(pStream->State.hStateChangedEvent);
+        rc = RTSemEventSignal(pStrmSt->State.hStateChangedEvent);
         AssertRC(rc);
 
         fProceed = false;
     }
     /* Is the stream not in a running state currently? */
-    else if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
+    else if (!(HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
         fProceed = false;
     /* Nothing to process? */
     else if (!cbToProcess)
         fProceed = false;
 
-    if ((HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
-    {
-        Log3Func(("[SD%RU8]: BCIS set\n", pStream->u8SD));
-        fProceed = false;
-    }
-
     if (!fProceed)
     {
-        Log3Func(("[SD%RU8]: Skipping\n", pStream->u8SD));
-
-        rc = RTCritSectLeave(&pStream->State.CritSect);
-        AssertRC(rc);
-
         if (pcbProcessed)
             *pcbProcessed = 0;
         return VINF_SUCCESS;
     }
 
+    LogFlowFunc(("enmSrc=%RU32, cbToProcess=%RU32\n", enmSrc, cbToProcess));
+
     /* Sanity checks. */
-    Assert(pStream->u8SD <= HDA_MAX_STREAMS);
-    Assert(pStream->u64BDLBase);
-    Assert(pStream->u32CBL);
+    Assert(pStrmSt->u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
+    Assert(pStrmSt->u64BDLBase);
+    Assert(pStrmSt->u32CBL);
 
     /* State sanity checks. */
-    Assert(pStream->State.fInReset == false);
-    Assert(HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) <= pStream->u32CBL);
-
-    bool fInterrupt = false;
-
-#ifdef DEBUG_andy
-//# define DEBUG_SIMPLE
-#endif
-
-#ifdef DEBUG_SIMPLE
-    uint8_t u8FIFO[_16K+1];
-    size_t u8FIFOff = 0;
-#endif
-
-    uint32_t cbLeft           = cbToProcess;
-    uint32_t cbTotal          = 0;
-    uint32_t cbChunk          = 0;
-    uint32_t cbChunkProcessed = 0;
+    Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false);
 
-    /* Set the FIFORDY bit on the stream while doing the transfer. */
-    HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+    uint32_t cbProcessedTotal = 0;
+    bool     fIsComplete      = false;
 
-    while (cbLeft)
+    while (cbToProcess)
     {
         /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
-        if (hdaStreamNeedsNextBDLE(pThis, pStream))
-        {
-            rc = hdaStreamGetNextBDLE(pThis, pStream);
-            if (RT_FAILURE(rc))
-                break;
-        }
+        if (hdaStreamNeedsNextBDLE(pThis, pStrmSt))
+            hdaStreamGetNextBDLE(pThis, pStrmSt);
 
-        cbChunk          = hdaStreamGetTransferSize(pThis, pStream, cbLeft);
-        cbChunkProcessed = 0;
+        /* Set the FIFORDY bit on the stream while doing the transfer. */
+        HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
 
-        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
-            rc = hdaReadAudio(pThis, pStream, cbChunk, &cbChunkProcessed);
-        else
+        uint32_t cbProcessed = 0;
+        switch (enmSrc)
         {
-#ifndef DEBUG_SIMPLE
-            rc = hdaWriteAudio(pThis, pStream, cbChunk, &cbChunkProcessed);
-#else
-            void    *pvBuf = u8FIFO + u8FIFOff;
-            int32_t cbBuf  = cbChunk;
-
-            PHDABDLE pBDLE = &pStream->State.BDLE;
-
-            if (cbBuf)
-                rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
-                                       pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
-                                       pvBuf, cbBuf);
-
-            cbChunkProcessed = cbChunk;
-
-            hdaBDLEUpdate(pBDLE, cbChunkProcessed, cbChunkProcessed);
-
-            u8FIFOff += cbChunkProcessed;
-            Assert((u8FIFOff & 1) == 0);
-            Assert(u8FIFOff <= sizeof(u8FIFO));
+            case PI_INDEX:
+                rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkLineIn, cbToProcess, &cbProcessed);
+                break;
+            case PO_INDEX:
+                rc = hdaWriteAudio(pThis, pStrmSt, cbToProcess, &cbProcessed);
+                break;
+#ifdef VBOX_WITH_HDA_MIC_IN
+            case MC_INDEX:
+                rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkMicIn, cbToProcess, &cbProcessed);
+                break;
 #endif
+            default:
+                AssertMsgFailed(("Unsupported source index %ld\n", enmSrc));
+                rc = VERR_NOT_SUPPORTED;
+                break;
         }
 
-        if (RT_FAILURE(rc))
-            break;
-
-        hdaStreamTransferUpdate(pThis, pStream, cbChunkProcessed);
-
-        Assert(cbLeft >= cbChunkProcessed);
-        cbLeft  -= cbChunkProcessed;
-        cbTotal += cbChunkProcessed;
+        /* Remove the FIFORDY bit again. */
+        HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
 
-        if (rc == VINF_EOF)
-            break;
-
-        if (hdaStreamTransferIsComplete(pThis, pStream, &fInterrupt))
+        if (RT_FAILURE(rc))
             break;
-    }
 
-    /* Remove the FIFORDY bit again. */
-    HDA_STREAM_REG(pThis, STS, pStream->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+        hdaStreamTransferUpdate(pThis, pStrmSt, cbProcessed);
 
-    LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbTotal, cbToProcess, rc));
+        cbToProcess      -= RT_MIN(cbToProcess, cbProcessed);
+        cbProcessedTotal += cbProcessed;
 
-#ifdef DEBUG_SIMPLE
-# ifdef HDA_DEBUG_DUMP_PCM_DATA
-        RTFILE fh;
-        RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio.pcm",
-                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-        RTFileWrite(fh, u8FIFO, u8FIFOff, NULL);
-        RTFileClose(fh);
-# endif
+        LogFlowFunc(("cbProcessed=%RU32, cbToProcess=%RU32, cbProcessedTotal=%RU32, rc=%Rrc\n",
+                     cbProcessed, cbToProcess, cbProcessedTotal, rc));
 
-     AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, u8FIFO, u8FIFOff,
-                         NULL /* pcbWritten */);
-#endif /* DEBUG_SIMPLE */
+        if (rc == VINF_EOF)
+            fIsComplete = true;
 
-    if (fInterrupt)
-    {
-        /**
-         * Set the BCIS (Buffer Completion Interrupt Status) flag as the
-         * last byte of data for the current descriptor has been fetched
-         * from memory and put into the DMA FIFO.
-         *
-         * Speech synthesis works fine on Mac Guest if this bit isn't set
-         * but in general sound quality gets worse.
-         *
-         * This must be set in *any* case.
-         */
-        HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
-        Log3Func(("[SD%RU8]: BCIS: Set\n", pStream->u8SD));
+        if (!fIsComplete)
+            fIsComplete = hdaStreamTransferIsComplete(pThis, pStrmSt);
 
-        hdaProcessInterrupt(pThis);
+        if (fIsComplete)
+            break;
     }
 
     if (RT_SUCCESS(rc))
     {
         if (pcbProcessed)
-            *pcbProcessed = cbTotal;
+            *pcbProcessed = cbProcessedTotal;
     }
 
-    int rc2 = RTCritSectLeave(&pStream->State.CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
 #endif /* IN_RING3 */
@@ -4522,9 +3361,9 @@ static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess
  */
 PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
 {
-    PHDASTATE   pThis  = PDMINS_2_DATA(pDevIns, PHDASTATE);
+    RT_NOREF(pvUser);
+    PHDASTATE   pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
     int         rc;
-    RT_NOREF_PV(pvUser);
 
     /*
      * Look up and log.
@@ -4536,14 +3375,14 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
     uint32_t        offRegLog = offReg;
 #endif
 
-    Log3Func(("offReg=%#x cb=%#x\n", offReg, cb));
+    LogFunc(("offReg=%#x cb=%#x\n", offReg, cb));
     Assert(cb == 4); Assert((offReg & 3) == 0);
 
     if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
-        LogFunc(("Access to registers except GCTL is blocked while reset\n"));
+        LogFunc(("\tAccess to registers except GCTL is blocked while reset\n"));
 
     if (idxRegDsc == -1)
-        LogRel(("HDA: Invalid read access @0x%x (bytes=%u)\n", offReg, cb));
+        LogRel(("HDA: Invalid read access @0x%x (bytes=%d)\n", offReg, cb));
 
     if (idxRegDsc != -1)
     {
@@ -4554,7 +3393,7 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
              * Straight forward DWORD access.
              */
             rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, (uint32_t *)pv);
-            Log3Func(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
+            LogFunc(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
         }
         else
         {
@@ -4570,7 +3409,7 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
                 uint32_t        u32Tmp       = 0;
 
                 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, &u32Tmp);
-                Log3Func(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
+                LogFunc(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
                 if (rc != VINF_SUCCESS)
                     break;
                 u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
@@ -4589,7 +3428,7 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
     else
     {
         rc = VINF_IOM_MMIO_UNUSED_FF;
-        Log3Func(("\tHole at %x is accessed for read\n", offReg));
+        LogFunc(("\tHole at %x is accessed for read\n", offReg));
     }
 
     /*
@@ -4597,11 +3436,11 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
      */
 #ifdef LOG_ENABLED
     if (cbLog == 4)
-        Log3Func(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
+        LogFunc(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
     else if (cbLog == 2)
-        Log3Func(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
+        LogFunc(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
     else if (cbLog == 1)
-        Log3Func(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
+        LogFunc(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
 #endif
     return rc;
 }
@@ -4609,20 +3448,20 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
 
 DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, char const *pszLog)
 {
+    RT_NOREF(pszLog);
     if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
     {
-        LogRel2(("HDA: Warning: Access to register 0x%x is blocked while reset\n", idxRegDsc));
+        LogRel2(("HDA: Access to register 0x%x is blocked while reset\n", idxRegDsc));
         return VINF_SUCCESS;
     }
 
 #ifdef LOG_ENABLED
-    uint32_t const idxRegMem   = g_aHdaRegMap[idxRegDsc].mem_idx;
+    uint32_t idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
     uint32_t const u32CurValue = pThis->au32Regs[idxRegMem];
 #endif
     int rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pThis, idxRegDsc, u32Value);
-    Log3Func(("Written value %#x to %s[%d byte]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
-              g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
-    RT_NOREF1(pszLog);
+    LogFunc(("write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
+             g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
     return rc;
 }
 
@@ -4632,9 +3471,9 @@ DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, c
  */
 PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
 {
-    PHDASTATE pThis  = PDMINS_2_DATA(pDevIns, PHDASTATE);
+    RT_NOREF(pvUser);
+    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
     int       rc;
-    RT_NOREF_PV(pvUser);
 
     /*
      * The behavior of accesses that aren't aligned on natural boundraries is
@@ -4665,16 +3504,16 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
 #ifdef LOG_ENABLED
     uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
     if (idxRegDsc == -1)
-        Log3Func(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
+        LogFunc(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
     else if (cb == 4)
-        Log3Func(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+        LogFunc(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
     else if (cb == 2)
-        Log3Func(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+        LogFunc(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
     else if (cb == 1)
-        Log3Func(("@%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+        LogFunc(("@%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
 
     if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].size != cb)
-        Log3Func(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
+        LogFunc(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
 #endif
 
     /*
@@ -4683,7 +3522,9 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
     if (idxRegDsc != -1 && g_aHdaRegMap[idxRegDsc].size == cb)
     {
         rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "");
-        Log3Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
+#ifdef LOG_ENABLED
+        LogFunc(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
+#endif
     }
     /*
      * Partial or multiple register access, loop thru the requested memory.
@@ -4703,8 +3544,8 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
             idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
             u64Value <<= cbBefore * 8;
             u64Value  |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
-            Log3Func(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
-                      cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
+            LogFunc(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
+                     cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
         }
 
         /* Loop thru the write area, it may cover multiple registers. */
@@ -4719,14 +3560,14 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
                 if (cb < cbReg)
                 {
                     u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
-                    Log3Func(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
-                              g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
+                    LogFunc(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
+                             g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
                 }
 #ifdef LOG_ENABLED
-                uint32_t uLogOldVal = pThis->au32Regs[idxRegMem];
+                uint32_t const u32LogOldVal = pThis->au32Regs[idxRegMem];
 #endif
                 rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "*");
-                Log3Func(("\t%#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
+                LogFunc(("\t%#x -> %#x\n", u32LogOldVal, pThis->au32Regs[idxRegMem]));
             }
             else
             {
@@ -4766,12 +3607,11 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int)
-hdaPciIoRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                           RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, enmType);
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
-    PHDASTATE   pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev);
+    PHDASTATE pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev);
 
     /*
      * 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word.
@@ -4781,8 +3621,10 @@ hdaPciIoRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCP
      */
     Assert(enmType == PCI_ADDRESS_SPACE_MEM);
     int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
-                                   IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
+                                     IOMMMIO_FLAGS_READ_DWORD
+                                   | IOMMMIO_FLAGS_WRITE_PASSTHRU,
                                    hdaMMIOWrite, hdaMMIORead, "HDA");
+
     if (RT_FAILURE(rc))
         return rc;
 
@@ -4812,24 +3654,25 @@ hdaPciIoRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCP
 static int hdaSaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStrm)
 {
     RT_NOREF(pDevIns);
-#ifdef DEBUG
+#ifdef VBOX_STRICT
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 #endif
-    LogFlowFunc(("[SD%RU8]\n", pStrm->u8SD));
+
+    LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
 
     /* Save stream ID. */
-    int rc = SSMR3PutU8(pSSM, pStrm->u8SD);
+    int rc = SSMR3PutU8(pSSM, pStrm->u8Strm);
     AssertRCReturn(rc, rc);
-    Assert(pStrm->u8SD <= HDA_MAX_STREAMS);
+    Assert(pStrm->u8Strm <= 7); /** @todo Use a define. */
 
     rc = SSMR3PutStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE), 0 /*fFlags*/, g_aSSMStreamStateFields6, NULL);
     AssertRCReturn(rc, rc);
 
-#ifdef DEBUG /* Sanity checks. */
-    uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrm->u8SD),
-                                      HDA_STREAM_REG(pThis, BDPU, pStrm->u8SD));
-    uint16_t u16LVI     = HDA_STREAM_REG(pThis, LVI, pStrm->u8SD);
-    uint32_t u32CBL     = HDA_STREAM_REG(pThis, CBL, pStrm->u8SD);
+#ifdef VBOX_STRICT /* Sanity checks. */
+    uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrm->u8Strm),
+                                      HDA_STREAM_REG(pThis, BDPU, pStrm->u8Strm));
+    uint16_t u16LVI     = HDA_STREAM_REG(pThis, LVI, pStrm->u8Strm);
+    uint32_t u32CBL     = HDA_STREAM_REG(pThis, CBL, pStrm->u8Strm);
 
     hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
 
@@ -4846,7 +3689,7 @@ static int hdaSaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStrm)
                           0 /*fFlags*/, g_aSSMBDLEStateFields6, NULL);
     AssertRCReturn(rc, rc);
 
-#ifdef DEBUG /* Sanity checks. */
+#ifdef VBOX_STRICT /* Sanity checks. */
     PHDABDLE pBDLE = &pStrm->State.BDLE;
     if (u64BaseDMA)
     {
@@ -4880,20 +3723,28 @@ static DECLCALLBACK(int) hdaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     hdaCodecSaveState(pThis->pCodec, pSSM);
 
     /* Save MMIO registers. */
+    AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
     SSMR3PutU32(pSSM, RT_ELEMENTS(pThis->au32Regs));
     SSMR3PutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
 
     /* Save number of streams. */
-    SSMR3PutU32(pSSM, HDA_MAX_STREAMS);
+#ifdef VBOX_WITH_HDA_MIC_IN
+    SSMR3PutU32(pSSM, 3);
+#else
+    SSMR3PutU32(pSSM, 2);
+#endif
 
     /* Save stream states. */
-    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
-    {
-        int rc = hdaSaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
-        AssertRCReturn(rc, rc);
-    }
+    int rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStOut);
+    AssertRCReturn(rc, rc);
+#ifdef VBOX_WITH_HDA_MIC_IN
+    rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStMicIn);
+    AssertRCReturn(rc, rc);
+#endif
+    rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStLineIn);
+    AssertRCReturn(rc, rc);
 
-    return VINF_SUCCESS;
+    return rc;
 }
 
 
@@ -4942,7 +3793,7 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
         case HDA_SSM_VERSION_2:
         case HDA_SSM_VERSION_3:
             cRegs = 112;
-            AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= 112);
+            AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
             break;
 
         /* Since version 4 we store the register count to stay flexible. */
@@ -5016,28 +3867,25 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
             /* Note 2: The stream's saving order is/was fixed, so don't touch! */
 
             /* Output */
-            PHDASTREAM pStream = &pThis->aStreams[4];
-            rc = hdaStreamInit(pThis, pStream, 4 /* Stream descriptor, hardcoded */);
+            rc = hdaStreamInit(pThis, &pThis->StrmStOut,    4 /* Stream number, hardcoded */);
             if (RT_FAILURE(rc))
                 break;
-            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
-            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStOut.State.BDLE);
+            pThis->StrmStOut.State.uCurBDLE = pThis->StrmStOut.State.BDLE.State.u32BDLIndex;
 
             /* Microphone-In */
-            pStream = &pThis->aStreams[2];
-            rc = hdaStreamInit(pThis, pStream, 2 /* Stream descriptor, hardcoded */);
+            rc = hdaStreamInit(pThis, &pThis->StrmStMicIn,  2 /* Stream number, hardcoded */);
             if (RT_FAILURE(rc))
                 break;
-            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
-            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStMicIn.State.BDLE);
+            pThis->StrmStMicIn.State.uCurBDLE = pThis->StrmStMicIn.State.BDLE.State.u32BDLIndex;
 
             /* Line-In */
-            pStream = &pThis->aStreams[0];
-            rc = hdaStreamInit(pThis, pStream, 0 /* Stream descriptor, hardcoded */);
+            rc = hdaStreamInit(pThis, &pThis->StrmStLineIn, 0 /* Stream number, hardcoded */);
             if (RT_FAILURE(rc))
                 break;
-            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
-            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStLineIn.State.BDLE);
+            pThis->StrmStLineIn.State.uCurBDLE = pThis->StrmStLineIn.State.BDLE.State.u32BDLIndex;
             break;
         }
 
@@ -5055,26 +3903,26 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
             /* Load stream states. */
             for (uint32_t i = 0; i < cStreams; i++)
             {
-                uint8_t uSD;
-                rc = SSMR3GetU8(pSSM, &uSD);
+                uint8_t uStreamID;
+                rc = SSMR3GetU8(pSSM, &uStreamID);
                 if (RT_FAILURE(rc))
                     break;
 
-                PHDASTREAM pStrm = hdaStreamFromSD(pThis, uSD);
+                PHDASTREAM pStrm = hdaStreamFromID(pThis, uStreamID);
                 HDASTREAM  StreamDummy;
 
                 if (!pStrm)
                 {
-                    RT_ZERO(StreamDummy);
                     pStrm = &StreamDummy;
-                    LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uSD));
-                    break;
+                    LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uStreamID));
                 }
 
-                rc = hdaStreamInit(pThis, pStrm, uSD);
+                RT_BZERO(pStrm, sizeof(HDASTREAM));
+
+                rc = hdaStreamInit(pThis, pStrm, uStreamID);
                 if (RT_FAILURE(rc))
                 {
-                    LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uSD, rc));
+                    LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uStreamID, rc));
                     break;
                 }
 
@@ -5154,35 +4002,42 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
 
     if (RT_SUCCESS(rc))
     {
-        pThis->u64CORBBase  = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
-        pThis->u64RIRBBase  = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
-        pThis->u64DPBase    = RT_MAKE_U64(HDA_REG(pThis, DPLBASE),   HDA_REG(pThis, DPUBASE));
+        /*
+         * Update stuff after the state changes.
+         */
+        bool fEnableIn    = RT_BOOL(HDA_SDCTL(pThis, 0 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+#ifdef VBOX_WITH_HDA_MIC_IN
+        bool fEnableMicIn = RT_BOOL(HDA_SDCTL(pThis, 2 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+#endif
+        bool fEnableOut   = RT_BOOL(HDA_SDCTL(pThis, 4 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
 
-        /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
-        pThis->fDMAPosition = RT_BOOL(pThis->u64DPBase & RT_BIT_64(0));
+        PHDADRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+        {
+            rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, fEnableIn);
+            if (RT_FAILURE(rc))
+                break;
+#ifdef VBOX_WITH_HDA_MIC_IN
+            rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, fEnableMicIn);
+            if (RT_FAILURE(rc))
+                break;
+#endif
+            rc = pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, fEnableOut);
+            if (RT_FAILURE(rc))
+                break;
+        }
     }
 
     if (RT_SUCCESS(rc))
     {
-        for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
-        {
-            PHDASTREAM pStream = hdaStreamFromSD(pThis, i);
-            if (pStream)
-            {
-                /* Deactive first. */
-                int rc2 = hdaStreamSetActive(pThis, pStream, false);
-                AssertRC(rc2);
-
-                bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+        pThis->u64CORBBase  = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
+        pThis->u64RIRBBase  = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
+        pThis->u64DPBase    = RT_MAKE_U64(HDA_REG(pThis, DPLBASE),   HDA_REG(pThis, DPUBASE));
 
-                /* Activate, if needed. */
-                rc2 = hdaStreamSetActive(pThis, pStream, fActive);
-                AssertRC(rc2);
-            }
-        }
+        /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
+        pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
     }
-
-    if (RT_FAILURE(rc))
+    else
         LogRel(("HDA: Failed loading device state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
 
     LogFlowFuncLeaveRC(rc);
@@ -5196,16 +4051,15 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
  * @callback_method_impl{FNRTSTRFORMATTYPE}
  */
 static DECLCALLBACK(size_t) hdaDbgFmtBDLE(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
-                                          const char *pszType, void const *pvValue,
-                                          int cchWidth, int cchPrecision, unsigned fFlags,
-                                          void *pvUser)
+                                           const char *pszType, void const *pvValue,
+                                           int cchWidth, int cchPrecision, unsigned fFlags,
+                                           void *pvUser)
 {
-    RT_NOREF(pszType, cchWidth,  cchPrecision, fFlags, pvUser);
+    RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
     PHDABDLE pBDLE = (PHDABDLE)pvValue;
     return RTStrFormat(pfnOutput,  pvArgOutput, NULL, 0,
-                       "BDLE(idx:%RU32, off:%RU32, fifow:%RU32, IOC:%RTbool, DMA[%RU32 bytes @ 0x%x])",
-                       pBDLE->State.u32BDLIndex, pBDLE->State.u32BufOff, pBDLE->State.cbBelowFIFOW,  pBDLE->fIntOnCompletion,
-                       pBDLE->u32BufSize, pBDLE->u64BufAdr);
+                       "BDLE(idx:%RU32, off:%RU32, fifow:%RU32, DMA[%RU32 bytes @ 0x%x])",
+                       pBDLE->State.u32BDLIndex, pBDLE->State.u32BufOff, pBDLE->State.cbBelowFIFOW, pBDLE->u32BufSize, pBDLE->u64BufAdr);
 }
 
 /**
@@ -5216,7 +4070,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDCTL(PFNRTSTROUTPUT pfnOutput, void *pvArg
                                            int cchWidth, int cchPrecision, unsigned fFlags,
                                            void *pvUser)
 {
-    RT_NOREF(pszType, cchWidth,  cchPrecision, fFlags, pvUser);
+    RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
     uint32_t uSDCTL = (uint32_t)(uintptr_t)pvValue;
     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
                        "SDCTL(raw:%#x, DIR:%s, TP:%RTbool, STRIPE:%x, DEIE:%RTbool, FEIE:%RTbool, IOCE:%RTbool, RUN:%RTbool, RESET:%RTbool)",
@@ -5239,7 +4093,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDFIFOS(PFNRTSTROUTPUT pfnOutput, void *pvA
                                              int cchWidth, int cchPrecision, unsigned fFlags,
                                              void *pvUser)
 {
-    RT_NOREF(pszType, cchWidth,  cchPrecision, fFlags, pvUser);
+    RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
     uint32_t uSDFIFOS = (uint32_t)(uintptr_t)pvValue;
     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw:%#x, sdfifos:%RU8 B)", uSDFIFOS, hdaSDFIFOSToBytes(uSDFIFOS));
 }
@@ -5252,7 +4106,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDFIFOW(PFNRTSTROUTPUT pfnOutput, void *pvA
                                              int cchWidth, int cchPrecision, unsigned fFlags,
                                              void *pvUser)
 {
-    RT_NOREF(pszType, cchWidth,  cchPrecision, fFlags, pvUser);
+    RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
     uint32_t uSDFIFOW = (uint32_t)(uintptr_t)pvValue;
     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSDFIFOW, hdaSDFIFOWToBytes(uSDFIFOW));
 }
@@ -5265,7 +4119,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArg
                                            int cchWidth, int cchPrecision, unsigned fFlags,
                                            void *pvUser)
 {
-    RT_NOREF(pszType, cchWidth,  cchPrecision, fFlags, pvUser);
+    RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
     uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue;
     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
                        "SDSTS(raw:%#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)",
@@ -5276,10 +4130,10 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArg
                        RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)));
 }
 
-static int hdaDbgLookupRegByName(const char *pszArgs)
+static int hdaLookUpRegisterByName(const char *pszArgs)
 {
     int iReg = 0;
-    for (; iReg < HDA_NUM_REGS; ++iReg)
+    for (; iReg < HDA_NREGS; ++iReg)
         if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs))
             return iReg;
     return -1;
@@ -5290,136 +4144,61 @@ static void hdaDbgPrintRegister(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaInd
 {
     Assert(   pThis
            && iHdaIndex >= 0
-           && iHdaIndex < HDA_NUM_REGS);
+           && iHdaIndex < HDA_NREGS);
     pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]);
 }
 
 /**
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaDbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-    int iHdaRegisterIndex = hdaDbgLookupRegByName(pszArgs);
+    int iHdaRegisterIndex = hdaLookUpRegisterByName(pszArgs);
     if (iHdaRegisterIndex != -1)
         hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
     else
-    {
-        for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NUM_REGS; ++iHdaRegisterIndex)
+        for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NREGS; ++iHdaRegisterIndex)
             hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
-    }
-}
-
-static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
-{
-    Assert(   pThis
-           && iIdx >= 0
-           && iIdx < HDA_MAX_STREAMS);
-
-    const PHDASTREAM pStrm = &pThis->aStreams[iIdx];
-
-    pHlp->pfnPrintf(pHlp, "Stream #%d:\n", iIdx);
-    pHlp->pfnPrintf(pHlp, "\tSD%dCTL  : %R[sdctl]\n",   iIdx, HDA_STREAM_REG(pThis, CTL,   iIdx));
-    pHlp->pfnPrintf(pHlp, "\tSD%dCTS  : %R[sdsts]\n",   iIdx, HDA_STREAM_REG(pThis, STS,   iIdx));
-    pHlp->pfnPrintf(pHlp, "\tSD%dFIFOS: %R[sdfifos]\n", iIdx, HDA_STREAM_REG(pThis, FIFOS, iIdx));
-    pHlp->pfnPrintf(pHlp, "\tSD%dFIFOW: %R[sdfifow]\n", iIdx, HDA_STREAM_REG(pThis, FIFOW, iIdx));
-    pHlp->pfnPrintf(pHlp, "\tBDLE     : %R[bdle]\n",    &pStrm->State.BDLE);
 }
 
-static void hdaDbgPrintBDLE(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
+static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaStrmIndex)
 {
     Assert(   pThis
-           && iIdx >= 0
-           && iIdx < HDA_MAX_STREAMS);
-
-    const PHDASTREAM pStrm = &pThis->aStreams[iIdx];
-    const PHDABDLE   pBDLE = &pStrm->State.BDLE;
-
-    pHlp->pfnPrintf(pHlp, "Stream #%d BDLE:\n", iIdx);
-    pHlp->pfnPrintf(pHlp, "\t%R[bdle]\n",       pBDLE);
-
-    uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, iIdx),
-                                      HDA_STREAM_REG(pThis, BDPU, iIdx));
-    uint16_t u16LVI     = HDA_STREAM_REG(pThis, LVI, iIdx);
-    /*uint32_t u32CBL     = HDA_STREAM_REG(pThis, CBL, iIdx); - unused */
-
-    if (!u64BaseDMA)
-        return;
-
-    uint32_t cbBDLE = 0;
-    for (uint16_t i = 0; i < u16LVI + 1; i++)
-    {
-        uint8_t bdle[16]; /** @todo Use a define. */
-        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + i * 16, bdle, 16); /** @todo Use a define. */
-
-        uint64_t addr = *(uint64_t *)bdle;
-        uint32_t len  = *(uint32_t *)&bdle[8];
-        uint32_t ioc  = *(uint32_t *)&bdle[12];
-
-        pHlp->pfnPrintf(pHlp, "\t#%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n",
-                        i, addr, len, RT_BOOL(ioc & 0x1));
-
-        cbBDLE += len;
-    }
-
-    pHlp->pfnPrintf(pHlp, "Total: %RU32 bytes\n", cbBDLE);
-
-    pHlp->pfnPrintf(pHlp, "DMA counters (base @ 0x%llx):\n", pThis->u64DPBase);
-    if (!pThis->u64DPBase) /* No DMA base given? Bail out. */
-    {
-        pHlp->pfnPrintf(pHlp, "No counters found\n");
-        return;
-    }
-
-    for (int i = 0; i < u16LVI + 1; i++)
-    {
-        uint32_t uDMACnt;
-        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
-                          &uDMACnt, sizeof(uDMACnt));
-
-        pHlp->pfnPrintf(pHlp, "\t#%03d DMA @ 0x%x\n", i , uDMACnt);
-    }
+           && iHdaStrmIndex >= 0
+           && iHdaStrmIndex < 7);
+    pHlp->pfnPrintf(pHlp, "Dump of %d HDA Stream:\n", iHdaStrmIndex);
+    pHlp->pfnPrintf(pHlp, "SD%dCTL: %R[sdctl]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, CTL, iHdaStrmIndex));
+    pHlp->pfnPrintf(pHlp, "SD%dCTS: %R[sdsts]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, STS, iHdaStrmIndex));
+    pHlp->pfnPrintf(pHlp, "SD%dFIFOS: %R[sdfifos]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, FIFOS, iHdaStrmIndex));
+    pHlp->pfnPrintf(pHlp, "SD%dFIFOW: %R[sdfifow]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, FIFOW, iHdaStrmIndex));
 }
 
-static int hdaDbgLookupStrmIdx(PHDASTATE pThis, const char *pszArgs)
+static int hdaLookUpStreamIndex(PHDASTATE pThis, const char *pszArgs)
 {
     RT_NOREF(pThis, pszArgs);
-    /** @todo Add args parsing. */
+    /** @todo add args parsing */
     return -1;
 }
 
 /**
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaDbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
-    PHDASTATE   pThis         = PDMINS_2_DATA(pDevIns, PHDASTATE);
-    int         iHdaStreamdex = hdaDbgLookupStrmIdx(pThis, pszArgs);
-    if (iHdaStreamdex != -1)
-        hdaDbgPrintStream(pThis, pHlp, iHdaStreamdex);
-    else
-        for(iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
-            hdaDbgPrintStream(pThis, pHlp, iHdaStreamdex);
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaDbgInfoBDLE(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE   pThis         = PDMINS_2_DATA(pDevIns, PHDASTATE);
-    int         iHdaStreamdex = hdaDbgLookupStrmIdx(pThis, pszArgs);
-    if (iHdaStreamdex != -1)
-        hdaDbgPrintBDLE(pThis, pHlp, iHdaStreamdex);
+    int         iHdaStrmIndex = hdaLookUpStreamIndex(pThis, pszArgs);
+    if (iHdaStrmIndex != -1)
+        hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
     else
-        for(iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
-            hdaDbgPrintBDLE(pThis, pHlp, iHdaStreamdex);
+        for(iHdaStrmIndex = 0; iHdaStrmIndex < 7; ++iHdaStrmIndex)
+            hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
 }
 
 /**
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaDbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
@@ -5432,7 +4211,7 @@ static DECLCALLBACK(void) hdaDbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP
 /**
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaDbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
@@ -5445,7 +4224,7 @@ static DECLCALLBACK(void) hdaDbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFO
 /**
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaDbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
@@ -5486,62 +4265,45 @@ static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
-    LogFlowFuncEnter();
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
-    /*
-     * Stop the timer, if any.
-     */
-    hdaTimerMaybeStop(pThis);
-# endif
-
-    /* See 6.2.1. */
-    HDA_REG(pThis, GCAP)     = HDA_MAKE_GCAP(HDA_MAX_SDO /* Ouput streams */,
-                                             HDA_MAX_SDI /* Input streams */,
-                                             0           /* Bidirectional output streams */,
-                                             0           /* Serial data out signals */,
-                                             1           /* 64-bit */);
+    HDA_REG(pThis, GCAP)     = HDA_MAKE_GCAP(4,4,0,0,1); /* see 6.2.1 */
     HDA_REG(pThis, VMIN)     = 0x00;                     /* see 6.2.2 */
     HDA_REG(pThis, VMAJ)     = 0x01;                     /* see 6.2.3 */
-    /* Announce the full 60 words output payload. */
     HDA_REG(pThis, OUTPAY)   = 0x003C;                   /* see 6.2.4 */
-    /* Announce the full 29 words input payload. */
     HDA_REG(pThis, INPAY)    = 0x001D;                   /* see 6.2.5 */
     HDA_REG(pThis, CORBSIZE) = 0x42;                     /* see 6.2.1 */
     HDA_REG(pThis, RIRBSIZE) = 0x42;                     /* see 6.2.1 */
     HDA_REG(pThis, CORBRP)   = 0x0;
     HDA_REG(pThis, RIRBWP)   = 0x0;
 
+    LogFunc(("Resetting ...\n"));
+
+# ifndef VBOX_WITH_AUDIO_CALLBACKS
     /*
-     * Stop any audio currently playing and/or recording.
+     * Stop the timer, if any.
      */
-    AudioMixerSinkCtl(pThis->SinkFront.pMixSink,     AUDMIXSINKCMD_DISABLE);
-# ifdef VBOX_WITH_HDA_MIC_IN
-    AudioMixerSinkCtl(pThis->SinkMicIn.pMixSink,     AUDMIXSINKCMD_DISABLE);
-# endif
-    AudioMixerSinkCtl(pThis->SinkLineIn.pMixSink,    AUDMIXSINKCMD_DISABLE);
-# ifdef VBOX_WITH_HDA_51_SURROUND
-    AudioMixerSinkCtl(pThis->SinkCenterLFE.pMixSink, AUDMIXSINKCMD_DISABLE);
-    AudioMixerSinkCtl(pThis->SinkRear.pMixSink,      AUDMIXSINKCMD_DISABLE);
+    int rc2;
+    if (pThis->pTimer)
+    {
+        rc2 = TMTimerStop(pThis->pTimer);
+        AssertRC(rc2);
+    }
 # endif
 
     /*
-     * Set some sensible defaults for which HDA sinks
-     * are connected to which stream number.
-     *
-     * We use SD0 for input and SD4 for output by default.
-     * These stream numbers can be changed by the guest dynamically lateron.
+     * Stop any audio currently playing and/or recording.
      */
-#ifdef VBOX_WITH_HDA_MIC_IN
-    hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_MIC_IN    , 1 /* SD0 */, 0 /* Channel */);
-#endif
-    hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_LINE_IN   , 1 /* SD0 */, 0 /* Channel */);
-
-    hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_FRONT     , 5 /* SD4 */, 0 /* Channel */);
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
-    hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_REAR      , 5 /* SD4 */, 0 /* Channel */);
-#endif
+    PHDADRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+    {
+        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
+# ifdef VBOX_WITH_HDA_MIC_IN
+        /* Ignore rc. */
+        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
+# endif
+        /* Ditto. */
+        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
+        /* Ditto. */
+    }
 
     pThis->cbCorbBuf = 256 * sizeof(uint32_t); /** @todo Use a define here. */
 
@@ -5558,24 +4320,42 @@ static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
 
     pThis->u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns);
 
-    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+    for (uint8_t u8Strm = 0; u8Strm < 8; u8Strm++) /** @todo Use a define here. */
     {
-        /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
-        HDA_STREAM_REG(pThis, CTL, i) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN);
-        hdaStreamReset(pThis, &pThis->aStreams[i]);
-    }
+        PHDASTREAM pStrmSt = NULL;
+        if (u8Strm == 0)      /** @todo Implement dynamic stream IDs. */
+            pStrmSt = &pThis->StrmStLineIn;
+# ifdef VBOX_WITH_HDA_MIC_IN
+        else if (u8Strm == 2) /** @todo Implement dynamic stream IDs. */
+            pStrmSt = &pThis->StrmStMicIn;
+# endif
+        else if (u8Strm == 4) /** @todo Implement dynamic stream IDs. */
+            pStrmSt = &pThis->StrmStOut;
+
+        if (pStrmSt)
+        {
+            /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
+            HDA_STREAM_REG(pThis, CTL, u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN);
 
-    /* Clear stream tags <-> objects mapping table. */
-    RT_ZERO(pThis->aTags);
+            hdaStreamReset(pThis, pStrmSt, u8Strm);
+        }
+    }
 
     /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
     HDA_REG(pThis, STATESTS) = 0x1;
 
 # ifndef VBOX_WITH_AUDIO_CALLBACKS
-    hdaTimerMaybeStart(pThis);
+    /*
+     * Start timer again, if any.
+     */
+    if (pThis->pTimer)
+    {
+        LogFunc(("Restarting timer\n"));
+        rc2 = TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
+        AssertRC(rc2);
+    }
 # endif
 
-    LogFlowFuncLeave();
     LogRel(("HDA: Reset\n"));
 }
 
@@ -5584,6 +4364,7 @@ static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
  */
 static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
 {
+    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
     PHDADRIVER pDrv;
@@ -5595,9 +4376,16 @@ static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
         RTMemFree(pDrv);
     }
 
+    if (pThis->pMixer)
+    {
+        AudioMixerDestroy(pThis->pMixer);
+        pThis->pMixer = NULL;
+    }
+
     if (pThis->pCodec)
     {
-        hdaCodecDestruct(pThis->pCodec);
+        int rc = hdaCodecDestruct(pThis->pCodec);
+        AssertRC(rc);
 
         RTMemFree(pThis->pCodec);
         pThis->pCodec = NULL;
@@ -5609,8 +4397,9 @@ static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
     RTMemFree(pThis->pu64RirbBuf);
     pThis->pu64RirbBuf = NULL;
 
-    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
-        hdaStreamDestroy(&pThis->aStreams[i]);
+    hdaStreamDestroy(&pThis->StrmStLineIn);
+    hdaStreamDestroy(&pThis->StrmStMicIn);
+    hdaStreamDestroy(&pThis->StrmStOut);
 
     return VINF_SUCCESS;
 }
@@ -5665,7 +4454,7 @@ static int hdaAttachInternal(PPDMDEVINS pDevIns, PHDADRIVER pDrv, unsigned uLUN,
              * host backend. This might change in the future.
              */
             if (pDrv->uLUN == 0)
-                pDrv->Flags |= PDMAUDIODRVFLAGS_PRIMARY;
+                pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
 
             LogFunc(("LUN#%u: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
 
@@ -5717,36 +4506,10 @@ static DECLCALLBACK(void) hdaDetach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t
 }
 
 /**
- * Powers off the device.
- *
- * @param   pDevIns             Device instance to power off.
- */
-static DECLCALLBACK(void) hdaPowerOff(PPDMDEVINS pDevIns)
-{
-    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
-    LogRel2(("HDA: Powering off ...\n"));
-
-    /* Ditto goes for the codec, which in turn uses the mixer. */
-    hdaCodecPowerOff(pThis->pCodec);
-
-    /**
-     * Note: Destroy the mixer while powering off and *not* in hdaDestruct,
-     *       giving the mixer the chance to release any references held to
-     *       PDM audio streams it maintains.
-     */
-    if (pThis->pMixer)
-    {
-        AudioMixerDestroy(pThis->pMixer);
-        pThis->pMixer = NULL;
-    }
-}
-
-/**
- * Re-attaches a new driver to the device's driver chain.
+ * Re-attach.
  *
  * @returns VBox status code.
- * @param   pThis       Device instance to re-attach driver to.
+ * @param   pThis       Device instance.
  * @param   pDrv        Driver instance used for attaching to.
  *                      If NULL is specified, a new driver will be created and appended
  *                      to the driver list.
@@ -5983,35 +4746,29 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
         rc = AudioMixerCreate("HDA Mixer", 0 /* uFlags */, &pThis->pMixer);
         if (RT_SUCCESS(rc))
         {
-            /*
-             * Add mixer output sinks.
-             */
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Front",
-                                      AUDMIXSINKDIR_OUTPUT, &pThis->SinkFront.pMixSink);
+            /* Set a default audio format for our mixer. */
+            PDMAUDIOSTREAMCFG streamCfg;
+            streamCfg.uHz           = 44100;
+            streamCfg.cChannels     = 2;
+            streamCfg.enmFormat     = AUD_FMT_S16;
+            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+            rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
             AssertRC(rc);
-            rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Center / Subwoofer",
-                                      AUDMIXSINKDIR_OUTPUT, &pThis->SinkCenterLFE.pMixSink);
-            AssertRC(rc);
-            rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Rear",
-                                      AUDMIXSINKDIR_OUTPUT, &pThis->SinkRear.pMixSink);
-            AssertRC(rc);
-#else
-            rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output",
-                                      AUDMIXSINKDIR_OUTPUT, &pThis->SinkFront.pMixSink);
+
+            /* Add all required audio sinks. */
+            rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
+                                   AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
             AssertRC(rc);
-#endif
-            /*
-             * Add mixer input sinks.
-             */
-            rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In",
-                                      AUDMIXSINKDIR_INPUT, &pThis->SinkLineIn.pMixSink);
+
+            rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In",
+                                   AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
             AssertRC(rc);
-#ifdef VBOX_WITH_HDA_MIC_IN
-            rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In",
-                                      AUDMIXSINKDIR_INPUT, &pThis->SinkMicIn.pMixSink);
+
+            rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In",
+                                   AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
             AssertRC(rc);
-#endif
+
             /* There is no master volume control. Set the master to max. */
             PDMAUDIOVOLUME vol = { false, 255, 255 };
             rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
@@ -6026,12 +4783,13 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
         if (!pThis->pCodec)
             return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("Out of memory allocating HDA codec state"));
 
-        /* Set codec callbacks. */
-        pThis->pCodec->pfnMixerAddStream    = hdaMixerAddStream;
-        pThis->pCodec->pfnMixerRemoveStream = hdaMixerRemoveStream;
-        pThis->pCodec->pfnMixerSetStream    = hdaMixerSetStream;
-        pThis->pCodec->pfnMixerSetVolume    = hdaMixerSetVolume;
-        pThis->pCodec->pfnReset             = hdaCodecReset;
+        /* Audio driver callbacks for multiplexing. */
+        pThis->pCodec->pfnCloseIn   = hdaCloseIn;
+        pThis->pCodec->pfnCloseOut  = hdaCloseOut;
+        pThis->pCodec->pfnOpenIn    = hdaOpenIn;
+        pThis->pCodec->pfnOpenOut   = hdaOpenOut;
+        pThis->pCodec->pfnReset     = hdaCodecReset;
+        pThis->pCodec->pfnSetVolume = hdaSetVolume;
 
         pThis->pCodec->pHDAState = pThis; /* Assign HDA controller state to codec. */
 
@@ -6050,18 +4808,15 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
 
     if (RT_SUCCESS(rc))
     {
-        /*
-         * Create all hardware streams.
-         */
-        for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
-        {
-            rc = hdaStreamCreate(&pThis->aStreams[i], i /* uSD */);
-            AssertRC(rc);
-        }
+        rc = hdaStreamCreate(&pThis->StrmStLineIn);
+        AssertRC(rc);
+#ifdef VBOX_WITH_HDA_MIC_IN
+        rc = hdaStreamCreate(&pThis->StrmStMicIn);
+        AssertRC(rc);
+#endif
+        rc = hdaStreamCreate(&pThis->StrmStOut);
+        AssertRC(rc);
 
-        /*
-         * Initialize the driver chain.
-         */
         PHDADRIVER pDrv;
         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
         {
@@ -6069,20 +4824,17 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
              * Only primary drivers are critical for the VM to run. Everything else
              * might not worth showing an own error message box in the GUI.
              */
-            if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+            if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
                 continue;
 
             PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
             AssertPtr(pCon);
 
-            bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
+            bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
 #ifdef VBOX_WITH_HDA_MIC_IN
-            bool fValidMicIn  = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
-#endif
-            bool fValidOut    = AudioMixerStreamIsValid(pDrv->Front.pMixStrm);
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            /** @todo Anything to do here? */
+            bool fValidMicIn  = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
 #endif
+            bool fValidOut    = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
 
             if (    !fValidLineIn
 #ifdef VBOX_WITH_HDA_MIC_IN
@@ -6104,20 +4856,20 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
                 bool fWarn = false;
 
                 PDMAUDIOBACKENDCFG backendCfg;
-                int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
+                int rc2 = pCon->pfnGetConfiguration(pCon, &backendCfg);
                 if (RT_SUCCESS(rc2))
                 {
-                    if (backendCfg.cSources)
+                    if (backendCfg.cMaxHstStrmsIn)
                     {
 #ifdef VBOX_WITH_HDA_MIC_IN
                         /* If the audio backend supports two or more input streams at once,
                          * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
-                        if (backendCfg.cMaxStreamsIn >= 2)
+                        if (backendCfg.cMaxHstStrmsIn >= 2)
                             fWarn = !fValidLineIn || !fValidMicIn;
                         /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
                          * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
                          * One of the two simply is not in use then. */
-                        else if (backendCfg.cMaxStreamsIn == 1)
+                        else if (backendCfg.cMaxHstStrmsIn == 1)
                             fWarn = !fValidLineIn && !fValidMicIn;
                         /* Don't warn if our backend is not able of supporting any input streams at all. */
 #else
@@ -6127,16 +4879,14 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
                     }
 
                     if (   !fWarn
-                        && backendCfg.cSinks)
+                        && backendCfg.cMaxHstStrmsOut)
                     {
                         fWarn = !fValidOut;
                     }
                 }
                 else
-                {
-                    LogRel(("HDA: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
-                    fWarn = true;
-                }
+                    AssertReleaseMsgFailed(("Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n",
+                                            pDrv->uLUN, rc2));
 
                 if (fWarn)
                 {
@@ -6187,12 +4937,11 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
         /*
          * Debug and string formatter types.
          */
-        PDMDevHlpDBGFInfoRegister(pDevIns, "hda",         "HDA info. (hda [register case-insensitive])",     hdaDbgInfo);
-        PDMDevHlpDBGFInfoRegister(pDevIns, "hdabdle",     "HDA stream BDLE info. (hdabdle [stream number])", hdaDbgInfoBDLE);
-        PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm",     "HDA stream info. (hdastrm [stream number])",      hdaDbgInfoStream);
-        PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes",    "HDA codec nodes.",                                hdaDbgInfoCodecNodes);
-        PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].",      hdaDbgInfoCodecSelector);
-        PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer",    "HDA mixer state.",                                hdaDbgInfoMixer);
+        PDMDevHlpDBGFInfoRegister(pDevIns, "hda",         "HDA info. (hda [register case-insensitive])",    hdaInfo);
+        PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm",     "HDA stream info. (hdastrm [stream number])",     hdaInfoStream);
+        PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes",    "HDA codec nodes.",                               hdaInfoCodecNodes);
+        PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].",     hdaInfoCodecSelector);
+        PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer",    "HDA mixer state.",                               hdaInfoMixer);
 
         rc = RTStrFormatTypeRegister("bdle",    hdaDbgFmtBDLE,    NULL);
         AssertRC(rc);
@@ -6267,7 +5016,8 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
             pThis->uTimerTS    = TMTimerGet(pThis->pTimer);
             LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
 
-            hdaTimerMaybeStart(pThis);
+            /* Fire off timer. */
+            TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
         }
     }
 # else
@@ -6278,7 +5028,7 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
         {
             /* Only register primary driver.
              * The device emulation does the output multiplexing then. */
-            if (pDrv->Flags != PDMAUDIODRVFLAGS_PRIMARY)
+            if (pDrv->Flags != PDMAUDIODRVFLAG_PRIMARY)
                 continue;
 
             PDMAUDIOCALLBACK AudioCallbacks[2];
@@ -6368,7 +5118,7 @@ const PDMDEVREG g_DeviceICH6_HDA =
     /* pfnInitComplete */
     NULL,
     /* pfnPowerOff */
-    hdaPowerOff,
+    NULL,
     /* pfnSoftReset */
     NULL,
     /* u32VersionEnd */
diff --git a/src/VBox/Devices/Audio/DevIchAc97.cpp b/src/VBox/Devices/Audio_50/DevIchAc97.cpp
similarity index 52%
copy from src/VBox/Devices/Audio/DevIchAc97.cpp
copy to src/VBox/Devices/Audio_50/DevIchAc97.cpp
index cedaa62..9bd4811 100644
--- a/src/VBox/Devices/Audio/DevIchAc97.cpp
+++ b/src/VBox/Devices/Audio_50/DevIchAc97.cpp
@@ -26,9 +26,6 @@
 
 #include <iprt/assert.h>
 #ifdef IN_RING3
-# ifdef DEBUG
-#  include <iprt/file.h>
-# endif
 # include <iprt/mem.h>
 # include <iprt/string.h>
 # include <iprt/uuid.h>
@@ -45,114 +42,97 @@
 *   Defined Constants And Macros                                                                                                 *
 *********************************************************************************************************************************/
 
-#if 0
-/*
- * AC97_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust AC97_DEBUG_DUMP_PCM_DATA_PATH
- * to your needs before using this!
- */
-# define AC97_DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-#  define AC97_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-#  define AC97_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+#ifdef DEBUG
+//#define DEBUG_LUN
+# ifdef DEBUG_LUN
+#  define DEBUG_LUN_NUM 1
 # endif
-#endif
+#endif /* DEBUG */
 
-/** Current saved state version. */
-#define AC97_SSM_VERSION    1
-
-/** Timer frequency (in Hz) */
-#define AC97_TIMER_HZ       200
-
-#define AC97_SR_FIFOE RT_BIT(4)          /* rwc, FIFO error. */
-#define AC97_SR_BCIS  RT_BIT(3)          /* rwc, Buffer completion interrupt status. */
-#define AC97_SR_LVBCI RT_BIT(2)          /* rwc, Last valid buffer completion interrupt. */
-#define AC97_SR_CELV  RT_BIT(1)          /* ro,  Current equals last valid. */
-#define AC97_SR_DCH   RT_BIT(0)          /* ro,  Controller halted. */
-#define AC97_SR_VALID_MASK (RT_BIT(5) - 1)
-#define AC97_SR_WCLEAR_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
-#define AC97_SR_RO_MASK (AC97_SR_DCH | AC97_SR_CELV)
-#define AC97_SR_INT_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
-
-#define AC97_CR_IOCE  RT_BIT(4)         /* rw,   Interrupt On Completion Enable. */
-#define AC97_CR_FEIE  RT_BIT(3)         /* rw    FIFO Error Interrupt Enable. */
-#define AC97_CR_LVBIE RT_BIT(2)         /* rw    Last Valid Buffer Interrupt Enable. */
-#define AC97_CR_RR    RT_BIT(1)         /* rw    Reset Registers. */
-#define AC97_CR_RPBM  RT_BIT(0)         /* rw    Run/Pause Bus Master. */
-#define AC97_CR_VALID_MASK (RT_BIT(5) - 1)
-#define AC97_CR_DONT_CLEAR_MASK (AC97_CR_IOCE | AC97_CR_FEIE | AC97_CR_LVBIE)
-
-#define AC97_GC_WR    4                 /* rw    Warm reset. */
-#define AC97_GC_CR    2                 /* rw    Cold reset. */
-#define AC97_GC_VALID_MASK (RT_BIT(6) - 1)
-
-#define AC97_GS_MD3   RT_BIT(17)        /* rw */
-#define AC97_GS_AD3   RT_BIT(16)        /* rw */
-#define AC97_GS_RCS   RT_BIT(15)        /* rwc */
-#define AC97_GS_B3S12 RT_BIT(14)        /* ro */
-#define AC97_GS_B2S12 RT_BIT(13)        /* ro */
-#define AC97_GS_B1S12 RT_BIT(12)        /* ro */
-#define AC97_GS_S1R1  RT_BIT(11)        /* rwc */
-#define AC97_GS_S0R1  RT_BIT(10)        /* rwc */
-#define AC97_GS_S1CR  RT_BIT(9)         /* ro */
-#define AC97_GS_S0CR  RT_BIT(8)         /* ro */
-#define AC97_GS_MINT  RT_BIT(7)         /* ro */
-#define AC97_GS_POINT RT_BIT(6)         /* ro */
-#define AC97_GS_PIINT RT_BIT(5)         /* ro */
-#define AC97_GS_RSRVD (RT_BIT(4)|RT_BIT(3))
-#define AC97_GS_MOINT RT_BIT(2)         /* ro */
-#define AC97_GS_MIINT RT_BIT(1)         /* ro */
-#define AC97_GS_GSCI  RT_BIT(0)         /* rwc */
-#define AC97_GS_RO_MASK (AC97_GS_B3S12 |                   \
-                         AC97_GS_B2S12 |                   \
-                         AC97_GS_B1S12 |                   \
-                         AC97_GS_S1CR  |                   \
-                         AC97_GS_S0CR  |                   \
-                         AC97_GS_MINT  |                   \
-                         AC97_GS_POINT |                   \
-                         AC97_GS_PIINT |                   \
-                         AC97_GS_RSRVD |                   \
-                         AC97_GS_MOINT |                   \
-                         AC97_GS_MIINT)
-#define AC97_GS_VALID_MASK (RT_BIT(18) - 1)
-#define AC97_GS_WCLEAR_MASK (AC97_GS_RCS|AC97_GS_S1R1|AC97_GS_S0R1|AC97_GS_GSCI)
-
-/** @name Buffer Descriptor (BD).
- * @{ */
-#define AC97_BD_IOC RT_BIT(31)          /**< Interrupt on Completion. */
-#define AC97_BD_BUP RT_BIT(30)          /**< Buffer Underrun Policy. */
+#define AC97_SSM_VERSION 1
 
-#define AC97_BD_MAX_LEN_MASK 0xFFFE
-/** @} */
+#ifdef VBOX
+# define SOFT_VOLUME /** @todo Get rid of this crap. */
+#else
+# define SOFT_VOLUME
+#endif
 
-/** @name Extended Audio Status and Control Register (EACS).
+#define SR_FIFOE RT_BIT(4)          /* rwc, FIFO error. */
+#define SR_BCIS  RT_BIT(3)          /* rwc, Buffer completion interrupt status. */
+#define SR_LVBCI RT_BIT(2)          /* rwc, Last valid buffer completion interrupt. */
+#define SR_CELV  RT_BIT(1)          /* ro,  Current equals last valid. */
+#define SR_DCH   RT_BIT(0)          /* ro,  Controller halted. */
+#define SR_VALID_MASK (RT_BIT(5) - 1)
+#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+#define SR_RO_MASK (SR_DCH | SR_CELV)
+#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+
+#define CR_IOCE  RT_BIT(4)         /* rw,   Interrupt On Completion Enable. */
+#define CR_FEIE  RT_BIT(3)         /* rw    FIFO Error Interrupt Enable. */
+#define CR_LVBIE RT_BIT(2)         /* rw    */
+#define CR_RR    RT_BIT(1)         /* rw */
+#define CR_RPBM  RT_BIT(0)         /* rw */
+#define CR_VALID_MASK (RT_BIT(5) - 1)
+#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
+
+#define GC_WR    4              /* rw */
+#define GC_CR    2              /* rw */
+#define GC_VALID_MASK (RT_BIT(6) - 1)
+
+#define GS_MD3   RT_BIT(17)        /* rw */
+#define GS_AD3   RT_BIT(16)        /* rw */
+#define GS_RCS   RT_BIT(15)        /* rwc */
+#define GS_B3S12 RT_BIT(14)        /* ro */
+#define GS_B2S12 RT_BIT(13)        /* ro */
+#define GS_B1S12 RT_BIT(12)        /* ro */
+#define GS_S1R1  RT_BIT(11)        /* rwc */
+#define GS_S0R1  RT_BIT(10)        /* rwc */
+#define GS_S1CR  RT_BIT(9)         /* ro */
+#define GS_S0CR  RT_BIT(8)         /* ro */
+#define GS_MINT  RT_BIT(7)         /* ro */
+#define GS_POINT RT_BIT(6)         /* ro */
+#define GS_PIINT RT_BIT(5)         /* ro */
+#define GS_RSRVD (RT_BIT(4)|RT_BIT(3))
+#define GS_MOINT RT_BIT(2)         /* ro */
+#define GS_MIINT RT_BIT(1)         /* ro */
+#define GS_GSCI  RT_BIT(0)         /* rwc */
+#define GS_RO_MASK (GS_B3S12 |                   \
+                    GS_B2S12 |                   \
+                    GS_B1S12 |                   \
+                    GS_S1CR |                    \
+                    GS_S0CR |                    \
+                    GS_MINT |                    \
+                    GS_POINT |                   \
+                    GS_PIINT |                   \
+                    GS_RSRVD |                   \
+                    GS_MOINT |                   \
+                    GS_MIINT)
+#define GS_VALID_MASK (RT_BIT(18) - 1)
+#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
+
+/** @name Buffer Descriptor
  * @{ */
-#define AC97_EACS_VRA 1                 /**< Variable Rate Audio (4.2.1.1). */
-#define AC97_EACS_VRM 8                 /**< Variable Rate Mic Audio (4.2.1.1). */
+#define BD_IOC RT_BIT(31)          /**< Interrupt on Completion */
+#define BD_BUP RT_BIT(30)          /**< Buffer Underrun Policy */
 /** @} */
 
-/** @name Baseline Audio Register Set (BARS).
- * @{ */
-#define AC97_BARS_VOL_MASK              0x1f   /**< Volume mask for the Baseline Audio Register Set (5.7.2). */
-#define AC97_BARS_VOL_STEPS             31     /**< Volume steps for the Baseline Audio Register Set (5.7.2). */
-#define AC97_BARS_VOL_MUTE_SHIFT        15     /**< Mute bit shift for the Baseline Audio Register Set (5.7.2). */
-/** @} */
+#define EACS_VRA 1
+#define EACS_VRM 8
 
-/* AC'97 uses 1.5dB steps, we use 0.375dB steps: 1 AC'97 step equals 4 PDM steps. */
-#define AC97_DB_FACTOR                  4
+#define VOL_MASK 0x1f
+#define MUTE_SHIFT 15
 
-#define AC97_REC_MASK 7
+#define REC_MASK 7
 enum
 {
-    AC97_REC_MIC = 0,
-    AC97_REC_CD,
-    AC97_REC_VIDEO,
-    AC97_REC_AUX,
-    AC97_REC_LINE_IN,
-    AC97_REC_STEREO_MIX,
-    AC97_REC_MONO_MIX,
-    AC97_REC_PHONE
+    REC_MIC = 0,
+    REC_CD,
+    REC_VIDEO,
+    REC_AUX,
+    REC_LINE_IN,
+    REC_STEREO_MIX,
+    REC_MONO_MIX,
+    REC_PHONE
 };
 
 enum
@@ -193,16 +173,15 @@ enum
 };
 
 /* Codec models. */
-typedef enum
-{
-    AC97_CODEC_STAC9700 = 0,     /* SigmaTel STAC9700 */
-    AC97_CODEC_AD1980,           /* Analog Devices AD1980 */
-    AC97_CODEC_AD1981B           /* Analog Devices AD1981B */
-} AC97CODEC;
+enum {
+    Codec_STAC9700 = 0,     /* SigmaTel STAC9700 */
+    Codec_AD1980,           /* Analog Devices AD1980 */
+    Codec_AD1981B           /* Analog Devices AD1981B */
+};
 
 /* Analog Devices miscellaneous regiter bits used in AD1980. */
-#define AC97_AD_MISC_LOSEL       RT_BIT(5)   /* Surround (rear) goes to line out outputs. */
-#define AC97_AD_MISC_HPSEL       RT_BIT(10)  /* PCM (front) goes to headphone outputs. */
+#define AD_MISC_LOSEL       RT_BIT(5)   /* Surround (rear) goes to line out outputs. */
+#define AD_MISC_HPSEL       RT_BIT(10)  /* PCM (front) goes to headphone outputs. */
 
 #define ICHAC97STATE_2_DEVINS(a_pAC97)   ((a_pAC97)->pDevInsR3)
 
@@ -213,44 +192,43 @@ enum
 };
 
 /** Emits registers for a specific (Native Audio Bus Master BAR) NABMBAR. */
-#define AC97_NABMBAR_REGS(prefix, off)                                    \
-    enum {                                                                \
-        prefix ## _BDBAR = off,      /* Buffer Descriptor Base Address */ \
-        prefix ## _CIV   = off + 4,  /* Current Index Value */            \
-        prefix ## _LVI   = off + 5,  /* Last Valid Index */               \
-        prefix ## _SR    = off + 6,  /* Status Register */                \
-        prefix ## _PICB  = off + 8,  /* Position in Current Buffer */     \
-        prefix ## _PIV   = off + 10, /* Prefetched Index Value */         \
-        prefix ## _CR    = off + 11  /* Control Register */               \
+#define AC97_NABMBAR_REGS(prefix, off) \
+    enum {                             \
+        prefix ## _BDBAR = off,        \
+        prefix ## _CIV   = off + 4,    \
+        prefix ## _LVI   = off + 5,    \
+        prefix ## _SR    = off + 6,    \
+        prefix ## _PICB  = off + 8,    \
+        prefix ## _PIV   = off + 10,   \
+        prefix ## _CR    = off + 11    \
     }
 
 #ifndef VBOX_DEVICE_STRUCT_TESTCASE
 typedef enum
 {
-    AC97SOUNDSOURCE_PI_INDEX = 0, /** PCM in */
-    AC97SOUNDSOURCE_PO_INDEX,     /** PCM out */
-    AC97SOUNDSOURCE_MC_INDEX,     /** Mic in */
-    AC97SOUNDSOURCE_LAST_INDEX
+    PI_INDEX = 0, /** PCM in */
+    PO_INDEX,     /** PCM out */
+    MC_INDEX,     /** Mic in */
+    LAST_INDEX
 } AC97SOUNDSOURCE;
 
-AC97_NABMBAR_REGS(PI, AC97SOUNDSOURCE_PI_INDEX * 16);
-AC97_NABMBAR_REGS(PO, AC97SOUNDSOURCE_PO_INDEX * 16);
-AC97_NABMBAR_REGS(MC, AC97SOUNDSOURCE_MC_INDEX * 16);
+AC97_NABMBAR_REGS(PI, PI_INDEX * 16);
+AC97_NABMBAR_REGS(PO, PO_INDEX * 16);
+AC97_NABMBAR_REGS(MC, MC_INDEX * 16);
 #endif
 
 enum
 {
     /** NABMBAR: Global Control Register. */
-    AC97_GLOB_CNT = 0x2c,
+    GLOB_CNT = 0x2c,
     /** NABMBAR Global Status. */
-    AC97_GLOB_STA = 0x30,
+    GLOB_STA = 0x30,
     /** Codec Access Semaphore Register. */
-    AC97_CAS      = 0x34
+    CAS      = 0x34
 };
 
 #define AC97_PORT2IDX(a_idx)   ( ((a_idx) >> 4) & 3 )
 
-
 /*********************************************************************************************************************************
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
@@ -273,7 +251,7 @@ typedef struct AC97BMREGS
     uint8_t  civ;               /** ro 0, Current index value. */
     uint8_t  lvi;               /** rw 0, Last valid index. */
     uint16_t sr;                /** rw 1, Status register. */
-    uint16_t picb;              /** ro 0, Position in current buffer (in samples). */
+    uint16_t picb;              /** ro 0, Position in current buffer. */
     uint8_t  piv;               /** ro 0, Prefetched index value. */
     uint8_t  cr;                /** rw 0, Control register. */
     int      bd_valid;          /** Whether current BDLE is initialized or not. */
@@ -281,28 +259,23 @@ typedef struct AC97BMREGS
 } AC97BMREGS, *PAC97BMREGS;
 
 /**
- * Internal state of an AC'97 stream.
+ * Internal state of an AC97 stream.
  */
 typedef struct AC97STREAMSTATE
 {
-    /** Temporary FIFO write buffer. */
-    R3PTRTYPE(uint8_t *) au8FIFOW;
-    /** Size of the temporary FIFO write buffer. */
-    uint32_t             cbFIFOW;
-    /** Current write offset in FIFO write buffer. */
-    uint32_t             offFIFOW;
-    uint8_t              Padding;
+    /* Nothing yet. */
 } AC97STREAMSTATE, *PAC97STREAMSTATE;
 
 /**
- * Structure for keeping an AC'97 stream state.
+ * Structure for keeping an AC97 stream state.
+ *
+ * Contains only register values which do *not* change until a
+ * stream reset occurs.
  */
 typedef struct AC97STREAM
 {
     /** Stream number (SDn). */
     uint8_t         u8Strm;
-    /** Criticial section for this stream. */
-    RTCRITSECT      CritSect;
     /** Bus master registers of this stream. */
     AC97BMREGS      Regs;
     /** Internal state of this stream. */
@@ -311,14 +284,18 @@ typedef struct AC97STREAM
 
 typedef struct AC97INPUTSTREAM
 {
-    /** Mixer handle for input stream. */
-    R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
+    /** PCM line input stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
+    /** Mixer handle for line input stream. */
+    R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
 } AC97INPUTSTREAM, *PAC97INPUTSTREAM;
 
 typedef struct AC97OUTPUTSTREAM
 {
+    /** PCM output stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
     /** Mixer handle for output stream. */
-    R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
+    R3PTRTYPE(PAUDMIXSTREAM)           phStrmOut;
 } AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM;
 
 /**
@@ -354,36 +331,26 @@ typedef struct AC97DRIVER
 typedef struct AC97STATE
 {
     /** The PCI device state. */
-    PCIDevice               PciDev;
+    PDMPCIDEV               PciDev;
     /** R3 Pointer to the device instance. */
     PPDMDEVINSR3            pDevInsR3;
-    /** Global Control (Bus Master Control Register). */
+    /** Global Control (Bus Master Control Register) */
     uint32_t                glob_cnt;
-    /** Global Status (Bus Master Control Register). */
+    /** Global Status (Bus Master Control Register) */
     uint32_t                glob_sta;
-    /** Codec Access Semaphore Register (Bus Master Control Register). */
+    /** Codec Access Semaphore Register (Bus Master Control Register) */
     uint32_t                cas;
     uint32_t                last_samp;
     uint8_t                 mixer_data[256];
     /** Stream state for line-in. */
-    AC97STREAM              StreamLineIn;
+    AC97STREAM              StrmStLineIn;
     /** Stream state for microphone-in. */
-    AC97STREAM              StreamMicIn;
+    AC97STREAM              StrmStMicIn;
     /** Stream state for output. */
-    AC97STREAM              StreamOut;
-    /** Number of active (running) SDn streams. */
-    uint8_t                 cStreamsActive;
+    AC97STREAM              StrmStOut;
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     /** The timer for pumping data thru the attached LUN drivers. */
     PTMTIMERR3              pTimer;
-    /** Criticial section for timer. */
-    RTCRITSECT              csTimer;
-# if HC_ARCH_BITS == 32
-    uint32_t                Padding0;
-# endif
-    /** Flag indicating whether the timer is active or not. */
-    bool                    fTimerActive;
-    uint8_t                 u8Padding1[7];
     /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
     uint64_t                cTimerTicks;
     /** Timestamp of the last timer callback (ac97Timer).
@@ -391,17 +358,16 @@ typedef struct AC97STATE
     uint64_t                uTimerTS;
 #endif
 #ifdef VBOX_WITH_STATISTICS
-    uint8_t                 Padding1;
     STAMPROFILE             StatTimer;
     STAMCOUNTER             StatBytesRead;
     STAMCOUNTER             StatBytesWritten;
 #endif
     /** List of associated LUN drivers (AC97DRIVER). */
     RTLISTANCHOR            lstDrv;
-    /** The device's software mixer. */
+    /** The device' software mixer. */
     R3PTRTYPE(PAUDIOMIXER)  pMixer;
     /** Audio sink for PCM output. */
-    R3PTRTYPE(PAUDMIXSINK)  pSinkOut;
+    R3PTRTYPE(PAUDMIXSINK)  pSinkOutput;
     /** Audio sink for line input. */
     R3PTRTYPE(PAUDMIXSINK)  pSinkLineIn;
     /** Audio sink for microphone input. */
@@ -412,33 +378,26 @@ typedef struct AC97STATE
     PDMIBASE                IBase;
     /** Base port of the I/O space region. */
     RTIOPORT                IOPortBase[2];
+    /** Pointer to temporary scratch read/write buffer. */
+    R3PTRTYPE(uint8_t *)    pvReadWriteBuf;
+    /** Size of the temporary scratch read/write buffer. */
+    uint32_t                cbReadWriteBuf;
     /** Codec model. */
     uint32_t                uCodecModel;
 } AC97STATE, *PAC97STATE;
 
 #ifdef VBOX_WITH_STATISTICS
-AssertCompileMemberAlignment(AC97STATE, StatTimer,        8);
-AssertCompileMemberAlignment(AC97STATE, StatBytesRead,    8);
-AssertCompileMemberAlignment(AC97STATE, StatBytesWritten, 8);
+AssertCompileMemberAlignment(AC97STATE, StatTimer, 8);
 #endif
 
 #ifndef VBOX_DEVICE_STRUCT_TESTCASE
 
-static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource);
-static void ichac97DestroyOut(PAC97STATE pThis);
 DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
-static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm);
-static void ichac97StreamDestroy(PAC97STREAM pStream);
-static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream);
-static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream);
-static void ichac97StreamClose(PAC97STREAM pStream);
 static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
-static void ichac97TimerMaybeStart(PAC97STATE pThis);
-static void ichac97TimerMaybeStop(PAC97STATE pThis);
 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
 #endif
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
+static int ichac97TransferAudio(PAC97STATE pThis, AC97SOUNDSOURCE enmSrc, uint32_t cbElapsed);
 
 static void ichac97WarmReset(PAC97STATE pThis)
 {
@@ -450,27 +409,11 @@ static void ichac97ColdReset(PAC97STATE pThis)
     NOREF(pThis);
 }
 
-DECLINLINE(PAUDMIXSINK) ichac97IndexToSink(PAC97STATE pThis, uint8_t uIndex)
-{
-    AssertPtrReturn(pThis, NULL);
-
-    switch (uIndex)
-    {
-        case AC97SOUNDSOURCE_PI_INDEX: return pThis->pSinkLineIn; break;
-        case AC97SOUNDSOURCE_PO_INDEX: return pThis->pSinkOut;    break;
-        case AC97SOUNDSOURCE_MC_INDEX: return pThis->pSinkMicIn;  break;
-        default:       break;
-    }
-
-    AssertMsgFailed(("Wrong index %RU8\n", uIndex));
-    return NULL;
-}
-
 /** Fetches the buffer descriptor at _CIV. */
-static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStream)
+static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStrmSt)
 {
     PPDMDEVINS  pDevIns = ICHAC97STATE_2_DEVINS(pThis);
-    PAC97BMREGS pRegs   = &pStream->Regs;
+    PAC97BMREGS pRegs   = &pStrmSt->Regs;
 
     uint32_t u32[2];
 
@@ -482,319 +425,187 @@ static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStream)
     pRegs->bd.addr    = RT_H2LE_U32(u32[0] & ~3);
     pRegs->bd.ctl_len = RT_H2LE_U32(u32[1]);
 #endif
-    pRegs->picb       = pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK;
+    pRegs->picb       = pRegs->bd.ctl_len & 0xffff;
     LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
                   pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len >> 16,
-                  pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK,
-                 (pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK) << 1)); /** @todo r=andy Assumes 16bit samples. */
+                  pRegs->bd.ctl_len & 0xffff, (pRegs->bd.ctl_len & 0xffff) << 1));
 }
 
 /**
  * Update the BM status register
  */
-static void ichac97StreamUpdateSR(PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr)
+static void ichac97StreamUpdateStatus(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t new_sr)
 {
     PPDMDEVINS  pDevIns = ICHAC97STATE_2_DEVINS(pThis);
-    PAC97BMREGS pRegs   = &pStream->Regs;
+    PAC97BMREGS pRegs   = &pStrmSt->Regs;
 
-    bool fSignal = false;
-    int  iIRQL = 0;
+    bool fSignal   = false;
+    bool iIrqLevel = 0;
 
-    uint32_t new_mask = new_sr & AC97_SR_INT_MASK;
-    uint32_t old_mask = pRegs->sr  & AC97_SR_INT_MASK;
+    uint32_t new_mask = new_sr & SR_INT_MASK;
+    uint32_t old_mask = pRegs->sr  & SR_INT_MASK;
 
-    static uint32_t const masks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT };
+    static uint32_t const masks[] = { GS_PIINT, GS_POINT, GS_MINT };
 
     if (new_mask ^ old_mask)
     {
         /** @todo Is IRQ deasserted when only one of status bits is cleared? */
         if (!new_mask)
         {
-            fSignal = true;
-            iIRQL   = 0;
+            fSignal   = true;
+            iIrqLevel = 0;
         }
-        else if ((new_mask & AC97_SR_LVBCI) && (pRegs->cr & AC97_CR_LVBIE))
+        else if ((new_mask & SR_LVBCI) && (pRegs->cr & CR_LVBIE))
         {
-            fSignal = true;
-            iIRQL   = 1;
+            fSignal   = true;
+            iIrqLevel = 1;
         }
-        else if ((new_mask & AC97_SR_BCIS) && (pRegs->cr & AC97_CR_IOCE))
+        else if ((new_mask & SR_BCIS) && (pRegs->cr & CR_IOCE))
         {
-            fSignal = true;
-            iIRQL   = 1;
+            fSignal   = true;
+            iIrqLevel = 1;
         }
     }
 
     pRegs->sr = new_sr;
 
-    LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, IRQL=%d\n",
-                 pRegs->sr & AC97_SR_BCIS, pRegs->sr & AC97_SR_LVBCI, pRegs->sr, fSignal, iIRQL));
+    LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, iIrqLevel=%d\n",
+                 pRegs->sr & SR_BCIS, pRegs->sr & SR_LVBCI, pRegs->sr, fSignal, iIrqLevel));
 
     if (fSignal)
     {
-        if (iIRQL)
-            pThis->glob_sta |=  masks[pStream->u8Strm];
+        if (iIrqLevel)
+            pThis->glob_sta |=  masks[pStrmSt->u8Strm];
         else
-            pThis->glob_sta &= ~masks[pStream->u8Strm];
+            pThis->glob_sta &= ~masks[pStrmSt->u8Strm];
 
-        LogFlowFunc(("Setting IRQ level=%d\n", iIRQL));
-        PDMDevHlpPCISetIrq(pDevIns, 0, iIRQL);
+        LogFlowFunc(("set irq level=%d\n", !!iIrqLevel));
+        PDMDevHlpPCISetIrq(pDevIns, 0, !!iIrqLevel);
     }
 }
 
-/**
- * Returns whether an AC'97 stream is enabled or not.
- *
- * @returns IPRT status code.
- * @param   pThis               AC'97 device state.
- * @param   pStream             Stream to return status for.
- */
-static bool ichac97StreamIsEnabled(PAC97STATE pThis, PAC97STREAM pStream)
-{
-    AssertPtrReturn(pThis,   false);
-    AssertPtrReturn(pStream, false);
-
-    PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
-    bool fIsEnabled = RT_BOOL(AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
-
-    LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8Strm, fIsEnabled));
-    return fIsEnabled;
-}
-
-static int ichac97StreamEnable(PAC97STATE pThis, PAC97STREAM pStream, bool fEnable)
+static int ichac97StreamSetActive(PAC97STATE pThis, PAC97STREAM pStrmSt, bool fActive)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
-    AssertPtr(pSink);
-
-    const bool fIsEnabled = AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING;
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-    LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n",
-             pStream->u8Strm, fEnable, fIsEnabled, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive));
+    LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool\n", pStrmSt->u8Strm, fActive));
 
     int rc = VINF_SUCCESS;
 
-    if (fEnable != fIsEnabled)
+    PAC97DRIVER pDrv;
+    switch (pStrmSt->u8Strm)
     {
-        rc = ichac97StreamReOpen(pThis, pStream);
-        if (RT_SUCCESS(rc))
-            rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
-                                   fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
-        if (RT_SUCCESS(rc))
-        {
-            if (!fEnable)
+        case PI_INDEX:
+            RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
             {
-                if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
-                    pThis->cStreamsActive--;
+                int rc2 = pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+                                                        pDrv->LineIn.pStrmIn, fActive);
+                if (RT_SUCCESS(rc))
+                    rc = rc2;
+            }
+            break;
 
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-                ichac97TimerMaybeStop(pThis);
-#endif
+        case PO_INDEX:
+            RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+            {
+                int rc2 = pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+                                                         pDrv->Out.pStrmOut, fActive);
+                if (RT_SUCCESS(rc))
+                    rc = rc2;
             }
-            else
+            break;
+
+        case MC_INDEX:
+            RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
             {
-                pThis->cStreamsActive++;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-                ichac97TimerMaybeStart(pThis);
-#endif
+                int rc2 = pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+                                                        pDrv->MicIn.pStrmIn, fActive);
+                if (RT_SUCCESS(rc))
+                    rc = rc2;
             }
-        }
+            break;
+
+        default:
+            AssertMsgFailed(("Wrong index %RU32\n", pStrmSt->u8Strm));
+            rc = VERR_NOT_SUPPORTED;
+            break;
     }
 
-    LogFunc(("Returning %Rrc\n", rc));
     return rc;
 }
 
-static void ichac97StreamResetBMRegs(PAC97STATE pThis, PAC97STREAM pStream)
+static void ichac97StreamResetBMRegs(PAC97STATE pThis, PAC97STREAM pStrmSt)
 {
     AssertPtrReturnVoid(pThis);
-    AssertPtrReturnVoid(pStream);
+    AssertPtrReturnVoid(pStrmSt);
 
-    LogFunc(("[SD%RU8]\n", pStream->u8Strm));
+    LogFlowFuncEnter();
 
-    PAC97BMREGS pRegs = &pStream->Regs;
+    PAC97BMREGS pRegs = &pStrmSt->Regs;
 
     pRegs->bdbar    = 0;
     pRegs->civ      = 0;
     pRegs->lvi      = 0;
 
-    ichac97StreamEnable(pThis, pStream, false /* fActive */);
-
-    ichac97StreamUpdateSR(pThis, pStream, AC97_SR_DCH); /** @todo Do we need to do that? */
+    ichac97StreamUpdateStatus(pThis, pStrmSt, SR_DCH); /** @todo Do we need to do that? */
 
     pRegs->picb     = 0;
     pRegs->piv      = 0;
-    pRegs->cr       = pRegs->cr & AC97_CR_DONT_CLEAR_MASK;
+    pRegs->cr       = pRegs->cr & CR_DONT_CLEAR_MASK;
     pRegs->bd_valid = 0;
 
-    RT_ZERO(pThis->silence);
-}
-
-static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_PARAMETER);
-
-    LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream));
-
-    int rc = VINF_SUCCESS;
+    int rc = ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
+    AssertRC(rc);
 
-    pStream->u8Strm         = u8Strm;
-    pStream->State.cbFIFOW  = _4K; /** @todo Make FIFOW size configurable. */
-    pStream->State.offFIFOW = 0;
-    pStream->State.au8FIFOW = (uint8_t *)RTMemAllocZ(pStream->State.cbFIFOW);
-    if (pStream->State.au8FIFOW)
-    {
-        rc = RTCritSectInit(&pStream->CritSect);
-    }
-    else
-        rc = VERR_NO_MEMORY;
-
-    return rc;
-}
-
-static void ichac97StreamDestroy(PAC97STREAM pStream)
-{
-    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
-
-    if (pStream->State.au8FIFOW)
-    {
-        Assert(pStream->State.cbFIFOW);
-        RTMemFree(pStream->State.au8FIFOW);
-        pStream->State.au8FIFOW = NULL;
-    }
-
-    pStream->State.cbFIFOW  = 0;
-    pStream->State.offFIFOW = 0;
-
-    if (RTCritSectIsInitialized(&pStream->CritSect))
-        RTCritSectDelete(&pStream->CritSect);
-}
-
-static int ichac97StreamsInit(PAC97STATE pThis)
-{
-    LogFlowFuncEnter();
-
-    int rc = ichac97StreamInit    (&pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);
-    if (RT_SUCCESS(rc))
-        rc = ichac97StreamInit    (&pThis->StreamMicIn,  AC97SOUNDSOURCE_MC_INDEX);
-        if (RT_SUCCESS(rc))
-            rc = ichac97StreamInit(&pThis->StreamOut,    AC97SOUNDSOURCE_PO_INDEX);
-
-    /* Open all streams with the current AC'97 mixer settings. */
-    if (RT_SUCCESS(rc))
-    {
-        rc = ichac97StreamOpen        (pThis, &pThis->StreamLineIn);
-        if (RT_SUCCESS(rc))
-            rc = ichac97StreamOpen    (pThis, &pThis->StreamMicIn);
-            if (RT_SUCCESS(rc))
-                rc = ichac97StreamOpen(pThis, &pThis->StreamOut);
-    }
-
-    LogFlowFunc(("Returning %Rrc\n", rc));
-    return rc;
-}
-
-static void ichac97StreamsDestroy(PAC97STATE pThis)
-{
-    LogFlowFuncEnter();
-
-    ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_LINE);
-    ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_MIC);
-    ichac97DestroyOut(pThis);
-
-    ichac97StreamDestroy(&pThis->StreamLineIn);
-    ichac97StreamDestroy(&pThis->StreamMicIn);
-    ichac97StreamDestroy(&pThis->StreamOut);
+    RT_ZERO(pThis->silence);
 }
 
-static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal)
+static void ichac97MixerSet(PAC97STATE pThis, uint32_t u8Idx, uint16_t v)
 {
-    if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
+    if (u8Idx + 2 > sizeof(pThis->mixer_data))
     {
-        AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
+        AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
         return;
     }
 
-    pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal);
-    pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal);
+    pThis->mixer_data[u8Idx + 0] = RT_LO_U8(v);
+    pThis->mixer_data[u8Idx + 1] = RT_HI_U8(v);
 }
 
-static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx)
+static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t u8Idx)
 {
     uint16_t uVal;
 
-    if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
+    if (u8Idx + 2 > sizeof(pThis->mixer_data))
     {
-        AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
+        AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
         uVal = UINT16_MAX;
     }
     else
-        uVal = RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]);
+        uVal = RT_MAKE_U16(pThis->mixer_data[u8Idx + 0], pThis->mixer_data[u8Idx + 1]);
 
     return uVal;
 }
 
-static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
+#if 0 // unused
+static DECLCALLBACK(void) ichac97CloseIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
 {
-    AssertPtrReturnVoid(pThis);
-
+    NOREF(pThis);
+    NOREF(enmRecSource);
     LogFlowFuncEnter();
-
-    PAUDMIXSINK pSink;
-    switch (enmRecSource)
-    {
-        case PDMAUDIORECSOURCE_MIC:
-            pSink = pThis->pSinkMicIn;
-            break;
-        case PDMAUDIORECSOURCE_LINE:
-            pSink = pThis->pSinkLineIn;
-            break;
-        default:
-            AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
-            return;
-    }
-
-    PAC97DRIVER pDrv;
-    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
-    {
-        PAC97INPUTSTREAM pStream;
-        if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
-            pStream = &pDrv->MicIn;
-        else
-            pStream = &pDrv->LineIn;
-
-        if (pStream->pMixStrm)
-        {
-            AudioMixerSinkRemoveStream(pSink, pStream->pMixStrm);
-            AudioMixerStreamDestroy(pStream->pMixStrm);
-        }
-        pStream->pMixStrm = NULL;
-    }
 }
 
-static void ichac97DestroyOut(PAC97STATE pThis)
+static DECLCALLBACK(void) ichac97CloseOut(PAC97STATE pThis)
 {
-    AssertPtrReturnVoid(pThis);
-
+    NOREF(pThis);
     LogFlowFuncEnter();
-
-    PAC97DRIVER pDrv;
-    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
-    {
-        if (pDrv->Out.pMixStrm)
-        {
-            AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
-            AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
-
-            pDrv->Out.pMixStrm = NULL;
-        }
-    }
 }
+#endif
 
-static int ichac97CreateIn(PAC97STATE pThis,
-                           const char *pszName, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg)
+static int ichac97OpenIn(PAC97STATE pThis,
+                         const char *pszName, PDMAUDIORECSOURCE enmRecSource,
+                         PPDMAUDIOSTREAMCFG pCfg)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
@@ -806,7 +617,7 @@ static int ichac97CreateIn(PAC97STATE pThis,
         case PDMAUDIORECSOURCE_MIC:
             pSink = pThis->pSinkMicIn;
             break;
-        case PDMAUDIORECSOURCE_LINE:
+        case PDMAUDIORECSOURCE_LINE_IN:
             pSink = pThis->pSinkLineIn;
             break;
         default:
@@ -814,176 +625,133 @@ static int ichac97CreateIn(PAC97STATE pThis,
             return VERR_NOT_SUPPORTED;
     }
 
-    /* Update the sink's format. */
-    PDMAUDIOPCMPROPS PCMProps;
-    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
-    if (RT_SUCCESS(rc))
-        rc = AudioMixerSinkSetFormat(pSink, &PCMProps);
-
-    if (RT_FAILURE(rc))
-        return rc;
+    int rc = VINF_SUCCESS;
 
     PAC97DRIVER pDrv;
     RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     {
-        if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pszName))
+        char *pszDesc;
+        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
         {
-            rc = VERR_BUFFER_OVERFLOW;
+            rc = VERR_NO_MEMORY;
             break;
         }
 
-        PAC97INPUTSTREAM pStream;
+        PAC97INPUTSTREAM pStrmIn;
         if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
-            pStream = &pDrv->MicIn;
+            pStrmIn = &pDrv->MicIn;
         else
-            pStream = &pDrv->LineIn;
+            pStrmIn = &pDrv->LineIn;
 
-        AudioMixerSinkRemoveStream(pSink, pStream->pMixStrm);
+        rc = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pStrmIn->pStrmIn);
 
-        AudioMixerStreamDestroy(pStream->pMixStrm);
-        pStream->pMixStrm = NULL;
-
-        int rc2 = AudioMixerSinkCreateStream(pSink, pDrv->pConnector, pCfg, 0 /* fFlags */ , &pStream->pMixStrm);
-        if (RT_SUCCESS(rc2))
+        LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+        if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
         {
-            rc2 = AudioMixerSinkAddStream(pSink, pStream->pMixStrm);
-            LogFlowFunc(("LUN#%RU8: Created input \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
+            AudioMixerRemoveStream(pSink, pStrmIn->phStrmIn);
+            rc = AudioMixerAddStreamIn(pSink,
+                                       pDrv->pConnector, pStrmIn->pStrmIn,
+                                       0 /* uFlags */, &pStrmIn->phStrmIn);
         }
 
-        if (RT_SUCCESS(rc))
-            rc = rc2;
+        RTStrFree(pszDesc);
     }
 
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-static int ichac97CreateOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
+static int ichac97OpenOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
     AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
 
-    LogFunc(("%s\n", pszName));
-
-    /* Update the sink's format. */
-    PDMAUDIOPCMPROPS PCMProps;
-    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
-    if (RT_SUCCESS(rc))
-        rc = AudioMixerSinkSetFormat(pThis->pSinkOut, &PCMProps);
-
-    if (RT_FAILURE(rc))
-        return rc;
+    int rc = VINF_SUCCESS;
+    char *pszDesc;
 
     PAC97DRIVER pDrv;
     RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     {
-        if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
-                         pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"))
+        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
+                         pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
         {
-            rc = VERR_BUFFER_OVERFLOW;
+            rc = VERR_NO_MEMORY;
             break;
         }
 
-        AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
-
-        AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
-        pDrv->Out.pMixStrm = NULL;
-
-        int rc2 = AudioMixerSinkCreateStream(pThis->pSinkOut, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
-        if (RT_SUCCESS(rc2))
+        rc = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+        LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+        if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
         {
-            rc2 = AudioMixerSinkAddStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
-            LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
+            AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
+            rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
+                                        pDrv->pConnector, pDrv->Out.pStrmOut,
+                                        0 /* uFlags */, &pDrv->Out.phStrmOut);
         }
 
-        if (RT_SUCCESS(rc))
-            rc = rc2;
+        RTStrFree(pszDesc);
     }
 
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-/**
- * Opens an AC'97 stream, extended version.
- *
- * @returns IPRT status code.
- * @param   pThis               AC'97 device state.
- * @param   pStream             Stream to initialize.
- * @param   pCfg                Audio stream configuration to initialize the stream with.
- */
-static int ichac97StreamOpenEx(PAC97STATE pThis, PAC97STREAM pStream, PPDMAUDIOSTREAMCFG pCfg)
+static int ichac97StreamInitEx(PAC97STATE pThis, PAC97STREAM pStrmSt, uint8_t u8Strm, PPDMAUDIOSTREAMCFG pCfg)
 {
     AssertPtrReturn(pThis,             VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,           VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt,           VERR_INVALID_POINTER);
+    AssertReturn(u8Strm <= LAST_INDEX, VERR_INVALID_PARAMETER);
     AssertPtrReturn(pCfg,              VERR_INVALID_POINTER);
 
-    LogFunc(("[SD%RU8] pCfg=%p\n", pStream->u8Strm, pCfg));
+    pStrmSt->u8Strm = u8Strm;
+
+    LogFlowFunc(("u8Strm=%RU8, %RU32Hz, %RU8 %s\n",
+                 pStrmSt->u8Strm, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"));
 
     int rc;
-    switch (pStream->u8Strm)
+    switch (pStrmSt->u8Strm)
     {
-        case AC97SOUNDSOURCE_PI_INDEX:
-            rc = ichac97CreateIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE, pCfg);
+        case PI_INDEX:
+            rc = ichac97OpenIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE_IN, pCfg);
             break;
 
-        case AC97SOUNDSOURCE_MC_INDEX:
-            rc = ichac97CreateIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);
+        case MC_INDEX:
+            rc = ichac97OpenIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);
             break;
 
-        case AC97SOUNDSOURCE_PO_INDEX:
-            rc = ichac97CreateOut(pThis, "ac97.po", pCfg);
+        case PO_INDEX:
+            rc = ichac97OpenOut(pThis, "ac97.po", pCfg);
             break;
 
         default:
-            AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
+            rc = VERR_NOT_SUPPORTED;
             break;
     }
 
-    if (RT_FAILURE(rc))
-        LogRel2(("AC97: Error opening stream #%RU8, rc=%Rrc\n", pStream->u8Strm, rc));
-
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
-/**
- * Opens an AC'97 stream.
- * This will open an AC'97 stream with 2 (stereo) channels, 16-bit samples and
- * the last set sample rate in the AC'97 mixer for this stream.
- *
- * @returns IPRT status code.
- * @param   pThis               AC'97 device state.
- * @param   pStream             Stream to initialize.
- */
-static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
+static int ichac97StreamInit(PAC97STATE pThis, PAC97STREAM pStrmSt, uint8_t u8Strm)
 {
     int rc = VINF_SUCCESS;
 
-    LogFunc(("[SD%RU8]\n", pStream->u8Strm));
-
     PDMAUDIOSTREAMCFG streamCfg;
     RT_ZERO(streamCfg);
 
-    switch (pStream->u8Strm)
+    switch (u8Strm)
     {
-        case AC97SOUNDSOURCE_PI_INDEX:
-            streamCfg.uHz               = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
-            streamCfg.enmDir            = PDMAUDIODIR_IN;
-            streamCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
+        case PI_INDEX:
+            streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
             break;
 
-        case AC97SOUNDSOURCE_MC_INDEX:
-            streamCfg.uHz               = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
-            streamCfg.enmDir            = PDMAUDIODIR_IN;
-            streamCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
+        case MC_INDEX:
+            streamCfg.uHz = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
             break;
 
-        case AC97SOUNDSOURCE_PO_INDEX:
-            streamCfg.uHz               = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
-            streamCfg.enmDir            = PDMAUDIODIR_OUT;
-            streamCfg.DestSource.Dest   = PDMAUDIOPLAYBACKDEST_FRONT;
+        case PO_INDEX:
+            streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
             break;
 
         default:
@@ -991,150 +759,111 @@ static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
             break;
     }
 
-    if (RT_SUCCESS(rc))
+    if (RT_FAILURE(rc))
+        return rc;
+
+    if (streamCfg.uHz)
     {
-        if (streamCfg.uHz)
-        {
-            streamCfg.cChannels     = 2;
-            streamCfg.enmFormat     = PDMAUDIOFMT_S16;
-            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+        streamCfg.cChannels     = 2;
+        streamCfg.enmFormat     = AUD_FMT_S16;
+        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
 
-            rc = ichac97StreamOpenEx(pThis, pStream, &streamCfg);
-        }
-        else
-            rc = VERR_INVALID_PARAMETER;
+        return ichac97StreamInitEx(pThis, pStrmSt, u8Strm, &streamCfg);
     }
 
-    LogFlowFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8Strm, rc));
-    return rc;
+    /* If no frequency is given, disable the stream. */
+    return ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
 }
 
-static void ichac97StreamClose(PAC97STREAM pStream)
+static int ichac97StreamReInit(PAC97STATE pThis, PAC97STREAM pStrmSt)
 {
-    RT_NOREF(pStream);
-
-    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
-}
-
-/**
- * Re-opens an AC'97 stream on the backend side with the current AC'97 mixer
- * settings for this stream.
- *
- * @returns IPRT status code.
- * @param   pThis               AC'97 device state.
- * @param   pStream             Stream to re-open.
- */
-static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream)
-{
-    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
-
-    ichac97StreamClose(pStream);
-
-    return ichac97StreamOpen(pThis, pStream);
+    return ichac97StreamInit(pThis, pStrmSt, pStrmSt->u8Strm);
 }
 
-static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrm)
+static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrmSt)
 {
     AssertPtrReturnVoid(pThis);
-    AssertPtrReturnVoid(pStrm);
+    AssertPtrReturnVoid(pStrmSt);
 
-    LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
-
-    if (pStrm->State.au8FIFOW)
-    {
-        Assert(pStrm->State.cbFIFOW);
-        RT_BZERO(pStrm->State.au8FIFOW, pStrm->State.cbFIFOW);
-    }
-
-    pStrm->State.offFIFOW = 0;
+    LogFlowFunc(("uStrm=%RU8\n", pStrmSt->u8Strm));
 }
 
-static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
+static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
 {
-    bool    fCntlMuted;
-    uint8_t lCntlAtt, rCntlAtt;
+    int mute = (val >> MUTE_SHIFT) & 1;
+    uint8_t rvol = val & VOL_MASK;
+    uint8_t lvol = (val >> 8) & VOL_MASK;
 
-    /*
-     * From AC'97 SoundMax Codec AD1981A/AD1981B:
-     * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the
-     *  D5 or D13 bits are set to 1, their respective lower five volume bits are automatically
-     *  set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever
-     *  these bits are set to 1."
-     *
-     * Linux ALSA depends on this behavior.
-     */
-    /// @todo Does this apply to anything other than the master volume control?
-    if (uVal & RT_BIT(5))
-        uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
-    if (uVal & RT_BIT(13))
-        uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
-
-    fCntlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
-    lCntlAtt   = (uVal >> 8) & AC97_BARS_VOL_MASK;
-    rCntlAtt   = uVal & AC97_BARS_VOL_MASK;
-
-    /* For the master and headphone volume, 0 corresponds to 0dB attenuation. For the other
-     * volume controls, 0 means 12dB gain and 8 means unity gain.
-     */
-    if (index != AC97_Master_Volume_Mute && index != AC97_Headphone_Volume_Mute)
+    /* For the master volume, 0 corresponds to 0dB gain. But for the other
+     * volume controls, 0 corresponds to +12dB and 8 to 0dB. */
+    if (mt != PDMAUDIOMIXERCTL_VOLUME)
     {
-#ifndef VBOX_WITH_AC97_GAIN_SUPPORT
         /* NB: Currently there is no gain support, only attenuation. */
-        lCntlAtt = lCntlAtt < 8 ? 0 : lCntlAtt - 8;
-        rCntlAtt = rCntlAtt < 8 ? 0 : rCntlAtt - 8;
-#endif
+        lvol = lvol < 8 ? 0 : lvol - 8;
+        rvol = rvol < 8 ? 0 : rvol - 8;
     }
-    Assert(lCntlAtt <= 255 / AC97_DB_FACTOR);
-    Assert(rCntlAtt <= 255 / AC97_DB_FACTOR);
 
-    LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
-    LogFunc(("lAtt=%RU8, rAtt=%RU8 ", lCntlAtt, rCntlAtt));
+    /* AC'97 has 1.5dB steps; we use 0.375dB steps. */
+    rvol = 255 - rvol * 4;
+    lvol = 255 - lvol * 4;
 
-    /*
-     * For AC'97 volume controls, each additional step means -1.5dB attenuation with
-     * zero being maximum. In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX)
-     * steps, each -0.375dB, where 0 corresponds to -96dB and 255 corresponds to 0dB.
-     */
-    uint8_t lVol = PDMAUDIO_VOLUME_MAX - lCntlAtt * AC97_DB_FACTOR;
-    uint8_t rVol = PDMAUDIO_VOLUME_MAX - rCntlAtt * AC97_DB_FACTOR;
-
-    Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCntlMuted, lVol, rVol));
+    LogFunc(("mt=%ld, val=%RX32, mute=%RTbool\n", mt, val, RT_BOOL(mute)));
 
     int rc;
 
+#ifdef SOFT_VOLUME
     if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
     {
-        PDMAUDIOVOLUME Vol = { fCntlMuted, lVol, rVol };
-        switch (enmMixerCtl)
+        PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
+        switch (mt)
         {
-            case PDMAUDIOMIXERCTL_VOLUME_MASTER:
-                rc = AudioMixerSetMasterVolume(pThis->pMixer,    &Vol);
+            case PDMAUDIOMIXERCTL_VOLUME:
+                rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
                 break;
-            case PDMAUDIOMIXERCTL_FRONT:
-                rc = AudioMixerSinkSetVolume(pThis->pSinkOut,    &Vol);
+
+            case PDMAUDIOMIXERCTL_PCM:
+                rc = AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
                 break;
 
             case PDMAUDIOMIXERCTL_MIC_IN:
-                rc = AudioMixerSinkSetVolume(pThis->pSinkMicIn,  &Vol);
+                rc = AudioMixerSetSinkVolume(pThis->pSinkMicIn, &vol);
                 break;
 
             case PDMAUDIOMIXERCTL_LINE_IN:
-                rc = AudioMixerSinkSetVolume(pThis->pSinkLineIn, &Vol);
+                rc = AudioMixerSetSinkVolume(pThis->pSinkLineIn, &vol);
                 break;
 
             default:
-                AssertFailed();
                 rc = VERR_NOT_SUPPORTED;
                 break;
         }
     }
     else
-        rc = VINF_SUCCESS;
-
-    ichac97MixerSet(pThis, index, uVal);
+        rc = VERR_NOT_SUPPORTED;
 
     if (RT_FAILURE(rc))
-        LogFlowFunc(("Failed with %Rrc\n", rc));
+        return rc;
+#else
+    rc = VINF_SUCCESS;
+#endif /* SOFT_VOLUME */
+
+    rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
+    lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
+
+    /*
+     * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
+     * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
+     * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
+     * all lower 5 bits will read ones whenever these bits are set to `1.'"
+     *
+     *  Linux ALSA depends on this behavior.
+     */
+    if (val & RT_BIT(5))
+        val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
+    if (val & RT_BIT(13))
+        val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
+
+    ichac97MixerSet(pThis, index, val);
 
     return rc;
 }
@@ -1143,12 +872,12 @@ static PDMAUDIORECSOURCE ichac97IndextoRecSource(uint8_t i)
 {
     switch (i)
     {
-        case AC97_REC_MIC:     return PDMAUDIORECSOURCE_MIC;
-        case AC97_REC_CD:      return PDMAUDIORECSOURCE_CD;
-        case AC97_REC_VIDEO:   return PDMAUDIORECSOURCE_VIDEO;
-        case AC97_REC_AUX:     return PDMAUDIORECSOURCE_AUX;
-        case AC97_REC_LINE_IN: return PDMAUDIORECSOURCE_LINE;
-        case AC97_REC_PHONE:   return PDMAUDIORECSOURCE_PHONE;
+        case REC_MIC:     return PDMAUDIORECSOURCE_MIC;
+        case REC_CD:      return PDMAUDIORECSOURCE_CD;
+        case REC_VIDEO:   return PDMAUDIORECSOURCE_VIDEO;
+        case REC_AUX:     return PDMAUDIORECSOURCE_AUX;
+        case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE_IN;
+        case REC_PHONE:   return PDMAUDIORECSOURCE_PHONE;
         default:
             break;
     }
@@ -1161,26 +890,27 @@ static uint8_t ichac97RecSourceToIndex(PDMAUDIORECSOURCE rs)
 {
     switch (rs)
     {
-        case PDMAUDIORECSOURCE_MIC:     return AC97_REC_MIC;
-        case PDMAUDIORECSOURCE_CD:      return AC97_REC_CD;
-        case PDMAUDIORECSOURCE_VIDEO:   return AC97_REC_VIDEO;
-        case PDMAUDIORECSOURCE_AUX:     return AC97_REC_AUX;
-        case PDMAUDIORECSOURCE_LINE: return AC97_REC_LINE_IN;
-        case PDMAUDIORECSOURCE_PHONE:   return AC97_REC_PHONE;
+        case PDMAUDIORECSOURCE_MIC:     return REC_MIC;
+        case PDMAUDIORECSOURCE_CD:      return REC_CD;
+        case PDMAUDIORECSOURCE_VIDEO:   return REC_VIDEO;
+        case PDMAUDIORECSOURCE_AUX:     return REC_AUX;
+        case PDMAUDIORECSOURCE_LINE_IN: return REC_LINE_IN;
+        case PDMAUDIORECSOURCE_PHONE:   return REC_PHONE;
         default:
             break;
     }
 
     LogFlowFunc(("Unknown audio recording source %d using MIC\n", rs));
-    return AC97_REC_MIC;
+    return REC_MIC;
 }
 
 static void ichac97RecordSelect(PAC97STATE pThis, uint32_t val)
 {
-    uint8_t rs = val & AC97_REC_MASK;
-    uint8_t ls = (val >> 8) & AC97_REC_MASK;
+    uint8_t rs = val & REC_MASK;
+    uint8_t ls = (val >> 8) & REC_MASK;
     PDMAUDIORECSOURCE ars = ichac97IndextoRecSource(rs);
     PDMAUDIORECSOURCE als = ichac97IndextoRecSource(ls);
+    //AUD_set_record_source(&als, &ars);
     rs = ichac97RecSourceToIndex(ars);
     ls = ichac97RecSourceToIndex(als);
     ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8));
@@ -1217,15 +947,15 @@ static int ichac97MixerReset(PAC97STATE pThis)
     ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate         , 0xbb80);
     ichac97MixerSet(pThis, AC97_MIC_ADC_Rate            , 0xbb80);
 
-    if (pThis->uCodecModel == AC97_CODEC_AD1980)
+    if (pThis->uCodecModel == Codec_AD1980)
     {
         /* Analog Devices 1980 (AD1980) */
-        ichac97MixerSet(pThis, AC97_Reset                   , 0x0010); /* Headphones. */
+        ichac97MixerSet(pThis, AC97_Reset                   , 0x0010);    /* Headphones. */
         ichac97MixerSet(pThis, AC97_Vendor_ID1              , 0x4144);
         ichac97MixerSet(pThis, AC97_Vendor_ID2              , 0x5370);
         ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute   , 0x8000);
     }
-    else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
+    else if (pThis->uCodecModel == Codec_AD1981B)
     {
         /* Analog Devices 1981B (AD1981B) */
         ichac97MixerSet(pThis, AC97_Vendor_ID1              , 0x4144);
@@ -1239,10 +969,9 @@ static int ichac97MixerReset(PAC97STATE pThis)
     }
     ichac97RecordSelect(pThis, 0);
 
-    ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000);
-    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,         0x8808);
-    ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN,       0x8808);
-    ichac97MixerSetVolume(pThis, AC97_Mic_Volume_Mute,     PDMAUDIOMIXERCTL_MIC_IN,        0x8808);
+    ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME,  0x8000);
+    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM,     0x8808);
+    ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
 
     return VINF_SUCCESS;
 }
@@ -1252,109 +981,93 @@ static int ichac97MixerReset(PAC97STATE pThis)
  *
  * @return  IPRT status code.
  * @param   pThis
- * @param   pStream
+ * @param   pStrmSt
  * @param   cbMax
  * @param   pcbWritten
  */
-static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
+static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
 {
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt,    VERR_INVALID_POINTER);
+    AssertReturn(cbMax,         VERR_INVALID_PARAMETER);
     /* pcbWritten is optional. */
 
     PPDMDEVINS  pDevIns = ICHAC97STATE_2_DEVINS(pThis);
-    PAC97BMREGS pRegs   = &pStream->Regs;
-
-    uint32_t    uAddr   = pRegs->bd.addr;
+    PAC97BMREGS pRegs   = &pStrmSt->Regs;
 
-    uint32_t    cbWrittenTotal = 0;
-
-    Log3Func(("PICB=%RU16, cbToWrite=%RU32\n", pRegs->picb, cbToWrite));
-
-    uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */
-    if (!cbLeft)
+    uint32_t cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbMax);
+    if (!cbToWrite)
     {
         if (pcbWritten)
             *pcbWritten = 0;
         return VINF_EOF;
     }
 
-    int rc = VINF_SUCCESS;
-
-    Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW);
-    uint32_t  cbFIFOW  = pStream->State.cbFIFOW - pStream->State.offFIFOW;
-    uint8_t  *pu8FIFOW = &pStream->State.au8FIFOW[pStream->State.offFIFOW];
+    uint32_t addr = pRegs->bd.addr;
+    int      rc = VINF_SUCCESS;
+    uint32_t cbWrittenTotal = 0;
+    uint32_t cbToRead = 0;
 
-    uint32_t cbWritten = 0;
+    LogFlowFunc(("pReg=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbMax, cbToWrite));
 
-    while (cbLeft)
+    while (cbToWrite)
     {
-        uint32_t cbToRead = RT_MIN(cbLeft, cbFIFOW);
+        cbToRead = RT_MIN(cbToWrite, pThis->cbReadWriteBuf);
+        PDMDevHlpPhysRead(pDevIns, addr, pThis->pvReadWriteBuf, cbToRead); /** @todo Check rc? */
 
-        PDMDevHlpPhysRead(pDevIns, uAddr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */
+        uint32_t cbWritten;
 
-#ifdef AC97_DEBUG_DUMP_PCM_DATA
-        RTFILE fh;
-        RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm",
-                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-        RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);
-        RTFileClose(fh);
-#endif
-        /*
-         * Write data to the mixer sink.
-         */
-        rc = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY, pu8FIFOW, cbToRead, &cbWritten);
-        if (RT_FAILURE(rc))
-            break;
+        /* Just multiplex the output to the connected backends.
+         * No need to utilize the virtual mixer here (yet). */
+        PAC97DRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+        {
+            int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+                                                 pThis->pvReadWriteBuf, cbToRead, &cbWritten);
+            LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32\n", pDrv->uLUN, rc2, cbWritten)); NOREF(rc2);
+        }
 
-        /* Advance. */
-        Assert(cbLeft >= cbWritten);
-        cbLeft         -= cbWritten;
-        cbWrittenTotal += cbWritten;
-        uAddr          += cbWritten;
-        Assert(cbWrittenTotal <= cbToWrite);
+        LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbLeft=%RU32\n",
+                     cbToRead, cbToWrite, cbToWrite - cbWrittenTotal));
 
-        LogFlowFunc(("%RU32 / %RU32\n", cbWrittenTotal, cbToWrite));
+        Assert(cbToWrite >= cbToRead);
+        cbToWrite      -= cbToRead;
+        addr           += cbToRead;
+        cbWrittenTotal += cbToRead;
     }
 
-    /* Set new buffer descriptor address. */
-    pRegs->bd.addr = uAddr;
+    pRegs->bd.addr = addr;
 
     if (RT_SUCCESS(rc))
     {
-        if (!cbLeft) /* All data written? */
+        if (!cbToWrite) /* All data written? */
         {
-            if (cbWritten < 4)
+            if (cbToRead < 4)
             {
-                AssertMsgFailed(("Unable to save last written sample, cbWritten < 4 (is %RU32)\n", cbWritten));
+                AssertMsgFailed(("Unable to save last written sample, cbToRead < 4 (is %RU32)\n", cbToRead));
                 pThis->last_samp = 0;
             }
             else
-                pThis->last_samp = *(uint32_t *)&pStream->State.au8FIFOW[pStream->State.offFIFOW + cbWritten - 4];
+                pThis->last_samp = *(uint32_t *)&pThis->pvReadWriteBuf[cbToRead - 4];
         }
 
         if (pcbWritten)
             *pcbWritten = cbWrittenTotal;
     }
 
-    if (RT_FAILURE(rc))
-        LogFlowFunc(("Failed with %Rrc\n", rc));
-
+    LogFlowFunc(("cbWrittenTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
     return rc;
 }
 
 static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
 {
-    LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
-
     if (!(pThis->bup_flag & BUP_SET))
     {
         if (pThis->bup_flag & BUP_LAST)
         {
             unsigned int i;
             uint32_t *p = (uint32_t*)pThis->silence;
-            for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */
+            for (i = 0; i < sizeof(pThis->silence) / 4; i++)
                 *p++ = pThis->last_samp;
         }
         else
@@ -1367,13 +1080,28 @@ static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
     {
         uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
         uint32_t cbWrittenToStream;
+        int rc2;
 
-        int rc2 = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY,
-                                      pThis->silence, cbToWrite, &cbWrittenToStream);
-        if (RT_SUCCESS(rc2))
+        PAC97DRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
         {
-            if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
-                LogFlowFunc(("Warning: Only written %RU32 / %RU32 bytes, expect lags\n", cbWrittenToStream, cbToWrite));
+            if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+            {
+                rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+                                                 pThis->silence, cbToWrite, &cbWrittenToStream);
+                if (RT_SUCCESS(rc2))
+                {
+                    if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
+                        LogFlowFunc(("\tLUN#%RU8: Warning: Only written %RU32 / %RU32 bytes, expect lags\n",
+                                     pDrv->uLUN, cbWrittenToStream, cbToWrite));
+                }
+            }
+            else /* Stream disabled, not fatal. */
+            {
+                cbWrittenToStream = 0;
+                rc2 = VERR_NOT_AVAILABLE;
+                /* Keep going. */
+            }
         }
 
         /* Always report all data as being written;
@@ -1383,25 +1111,25 @@ static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
     }
 }
 
-static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
+static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t cbMax, uint32_t *pcbRead)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(cbToRead,   VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+    AssertReturn(cbMax,      VERR_INVALID_PARAMETER);
     /* pcbRead is optional. */
 
     PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
-    PAC97BMREGS pRegs  = &pStream->Regs;
+    PAC97BMREGS pRegs  = &pStrmSt->Regs;
 
     /* Select audio sink to process. */
-    AssertMsg(pStream->u8Strm != AC97SOUNDSOURCE_PO_INDEX, ("Can't read from output\n"));
-    PAUDMIXSINK pSink = pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
+    AssertMsg(pStrmSt->u8Strm != PO_INDEX, ("Can't read from output\n"));
+    PAUDMIXSINK pSink = pStrmSt->u8Strm == MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
     AssertPtr(pSink);
 
     uint32_t cbRead   = 0;
 
-    cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
-                      RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */
+    uint32_t cbMixBuf = cbMax;
+    uint32_t cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1), cbMixBuf);
 
     if (!cbToRead)
     {
@@ -1412,19 +1140,24 @@ static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbTo
 
     int rc;
 
-    rc = AudioMixerSinkRead(pSink, AUDMIXOP_BLEND, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbToRead, &cbRead);
-    if (   RT_SUCCESS(rc)
-        && cbRead)
+    uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbMixBuf);
+    if (pvMixBuf)
     {
-        PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbRead);
-        pRegs->bd.addr += cbRead;
+        rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pvMixBuf, cbToRead, &cbRead);
+        if (   RT_SUCCESS(rc)
+            && cbRead)
+        {
+            PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvMixBuf, cbRead);
+            pRegs->bd.addr += cbRead;
+        }
+
+        RTMemFree(pvMixBuf);
     }
+    else
+        rc = VERR_NO_MEMORY;
 
     if (RT_SUCCESS(rc))
     {
-        if (!cbRead)
-            rc = VINF_EOF;
-
         if (pcbRead)
             *pcbRead = cbRead;
     }
@@ -1434,46 +1167,6 @@ static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbTo
 
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
 
-static void ichac97TimerMaybeStart(PAC97STATE pThis)
-{
-    if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
-        return;
-
-    if (!pThis->pTimer)
-        return;
-
-    if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Alredy started? */
-        return;
-
-    LogFlowFunc(("Starting timer\n"));
-
-    /* Set timer flag. */
-    ASMAtomicXchgBool(&pThis->fTimerActive, true);
-
-    /* Update current time timestamp. */
-    pThis->uTimerTS = TMTimerGet(pThis->pTimer);
-
-    /* Fire off timer. */
-    TMTimerSet(pThis->pTimer, 0 /* u64Expire */);
-}
-
-static void ichac97TimerMaybeStop(PAC97STATE pThis)
-{
-    if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
-        return;
-
-    if (!pThis->pTimer)
-        return;
-
-    if (ASMAtomicReadBool(&pThis->fTimerActive) == false) /* Already stopped? */
-        return;
-
-    LogFlowFunc(("Stopping timer\n"));
-
-    /* Set timer flag. */
-    ASMAtomicXchgBool(&pThis->fTimerActive, false);
-}
-
 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
 {
     RT_NOREF(pDevIns);
@@ -1481,99 +1174,134 @@ static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void
     Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE));
     AssertPtr(pThis);
 
-    int rc = RTCritSectEnter(&pThis->csTimer);
-    if (RT_SUCCESS(rc))
-    {
-        STAM_PROFILE_START(&pThis->StatTimer, a);
+    STAM_PROFILE_START(&pThis->StatTimer, a);
 
-        uint64_t cTicksNow = TMTimerGet(pTimer);
+    uint32_t cbInMax  = 0;
+    uint32_t cbOutMin = UINT32_MAX;
 
-        /* Update current time timestamp. */
-        pThis->uTimerTS = cTicksNow;
+    PAC97DRIVER pDrv;
 
-        /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */
-        bool fDoNextTransfer = false;
+    uint64_t cTicksNow     = TMTimerGet(pTimer);
+    uint64_t cTicksElapsed = cTicksNow  - pThis->uTimerTS;
+    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
 
-        uint32_t cbToProcess;
+    pThis->uTimerTS = cTicksNow;
 
-        rc = AudioMixerSinkUpdate(pThis->pSinkLineIn);
-        if (RT_SUCCESS(rc))
-        {
-            cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkLineIn);
-            if (cbToProcess)
-                rc = ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbToProcess, NULL /* pcbProcessed */);
+    /*
+     * Calculate the mixer's (fixed) sampling rate.
+     */
+    AssertPtr(pThis->pMixer);
 
-            if (AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY)
-                fDoNextTransfer = true;
-        }
+    PDMAUDIOSTREAMCFG mixerStrmCfg;
+    int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
+    AssertRC(rc);
 
-        rc = AudioMixerSinkUpdate(pThis->pSinkMicIn);
-        if (RT_SUCCESS(rc))
-        {
-            cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkMicIn);
-            if (cbToProcess)
-                rc = ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbToProcess, NULL /* pcbProcessed */);
+    PDMPCMPROPS mixerStrmProps;
+    rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
+    AssertRC(rc);
 
-            if (AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY)
-                fDoNextTransfer = true;
-        }
+    uint32_t cMixerSamplesMin  = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
+    uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
 
-        rc = AudioMixerSinkUpdate(pThis->pSinkOut);
+    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+    {
+        uint32_t cbIn = 0;
+        uint32_t cbOut = 0;
+
+        rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
+                                              &cbIn, &cbOut, NULL /* cSamplesLive */);
         if (RT_SUCCESS(rc))
-        {
-            cbToProcess = AudioMixerSinkGetWritable(pThis->pSinkOut);
-            if (cbToProcess)
-                rc = ichac97TransferAudio(pThis, &pThis->StreamOut, cbToProcess, NULL /* pcbProcessed */);
+            rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
 
-            if (AudioMixerSinkGetStatus(pThis->pSinkOut) & AUDMIXSINK_STS_DIRTY)
-                fDoNextTransfer = true;
-        }
+        Log3Func(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
 
-        if (fDoNextTransfer)
+        /* If we there was an error handling (available) output or there simply is no output available,
+         * then calculate the minimum data rate which must be processed by the device emulation in order
+         * to function correctly.
+         *
+         * This is not the optimal solution, but as we have to deal with this on a timer-based approach
+         * (until we have the audio callbacks) we need to have device' DMA engines running. */
+        if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
         {
-            /* Kick the timer again. */
-            uint64_t cTicks = pThis->cTimerTicks;
-            /** @todo adjust cTicks down by now much cbOutMin represents. */
-            TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+            /* Use the mixer's (fixed) sampling rate. */
+            cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
         }
         else
         {
-            LogFunc(("Stopping timer\n"));
-            LogRel3(("AC97: Stopping timer\n"));
+            const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+            if (   RT_FAILURE(rc)
+                || !fIsActiveOut)
+            {
+                uint32_t cSamplesMin  = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+                uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
+
+                Log3Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
+
+                cbOut = RT_MAX(cbOut, cbSamplesMin);
+            }
         }
 
-        STAM_PROFILE_STOP(&pThis->StatTimer, a);
+        cbOutMin = RT_MIN(cbOutMin, cbOut);
+        cbInMax  = RT_MAX(cbInMax, cbIn);
+    }
 
-        int rc2 = RTCritSectLeave(&pThis->csTimer);
-        if (RT_SUCCESS(rc))
-            rc2 = rc;
+    Log3Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
+
+    if (cbOutMin == UINT32_MAX)
+        cbOutMin = 0;
+
+    /*
+     * Playback.
+     */
+    if (cbOutMin)
+    {
+        Assert(cbOutMin != UINT32_MAX);
+        ichac97TransferAudio(pThis, PO_INDEX, cbOutMin); /** @todo Add rc! */
     }
+
+    /*
+     * Recording.
+     */
+    if (cbInMax)
+        ichac97TransferAudio(pThis, PI_INDEX, cbInMax); /** @todo Add rc! */
+
+    /* Kick the timer again. */
+    uint64_t cTicks = pThis->cTimerTicks;
+    /** @todo adjust cTicks down by now much cbOutMin represents. */
+    TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+
+    STAM_PROFILE_STOP(&pThis->StatTimer, a);
 }
 
-#endif /* !VBOX_WITH_AUDIO_CALLBACKS */
+#endif
 
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int ichac97TransferAudio(PAC97STATE pThis, AC97SOUNDSOURCE enmSrc, uint32_t cbElapsed)
 {
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbProcessed is optional. */
-
-    int rc = RTCritSectEnter(&pStream->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
+    LogFlowFunc(("pThis=%p, enmSrc=%RU32, cbElapsed=%RU32\n", pThis, enmSrc, cbElapsed));
 
-    LogFunc(("[SD%RU8] cbToProcess=%RU32\n", pStream->u8Strm, cbToProcess));
+    PAC97STREAM pStrmSt;
+    switch (enmSrc)
+    {
+        case PI_INDEX: pStrmSt = &pThis->StrmStLineIn; break;
+        case MC_INDEX: pStrmSt = &pThis->StrmStMicIn;  break;
+        case PO_INDEX: pStrmSt = &pThis->StrmStOut;    break;
+        default:
+        {
+            AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
+            return VERR_NOT_SUPPORTED;
+        }
+    }
 
-    PAC97BMREGS pRegs = &pStream->Regs;
+    PAC97BMREGS pRegs = &pStrmSt->Regs;
 
-    if (pRegs->sr & AC97_SR_DCH) /* Controller halted? */
+    if (pRegs->sr & SR_DCH) /* Controller halted? */
     {
-        if (pRegs->cr & AC97_CR_RPBM) /* Bus master operation starts. */
+        if (pRegs->cr & CR_RPBM)
         {
-            switch (pStream->u8Strm)
+            switch (enmSrc)
             {
-                case AC97SOUNDSOURCE_PO_INDEX:
-                    ichac97WriteBUP(pThis, cbToProcess);
+                case PO_INDEX:
+                    ichac97WriteBUP(pThis, cbElapsed);
                     break;
 
                 default:
@@ -1581,42 +1309,18 @@ static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t
             }
         }
 
-        if (pcbProcessed)
-            *pcbProcessed = 0;
-
-        Log3Func(("[SD%RU8] Halted\n", pStream->u8Strm));
-
-        rc = RTCritSectLeave(&pStream->CritSect);
-        AssertRC(rc);
-
         return VINF_SUCCESS;
     }
 
-    /* BCIS flag still set? Skip iteration. */
-    if (pRegs->sr & AC97_SR_BCIS)
-    {
-        Log3Func(("[SD%RU8] BCIS set\n", pStream->u8Strm));
-
-        if (pcbProcessed)
-            *pcbProcessed = 0;
-
-        rc = RTCritSectLeave(&pStream->CritSect);
-        AssertRC(rc);
-
-        return VINF_SUCCESS;
-    }
-
-    uint32_t cbLeft  = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcess);
-    uint32_t cbTotal = 0;
-
-    Log3Func(("[SD%RU8] cbLeft=%RU32\n", pStream->u8Strm, cbLeft));
+    int rc = VINF_SUCCESS;
+    uint32_t cbWrittenTotal = 0;
 
-    while (cbLeft)
+    while (cbElapsed >> 1)
     {
         if (!pRegs->bd_valid)
         {
             LogFlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));
-            ichac97StreamFetchBDLE(pThis, pStream);
+            ichac97StreamFetchBDLE(pThis, pStrmSt);
         }
 
         if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
@@ -1625,114 +1329,96 @@ static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t
                          pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
             if (pRegs->civ == pRegs->lvi)
             {
-                pRegs->sr |= AC97_SR_DCH; /** @todo r=andy Also set CELV? */
+                pRegs->sr |= SR_DCH; /* CELV? */
                 pThis->bup_flag = 0;
 
                 rc = VINF_EOF;
                 break;
             }
 
-            pRegs->sr &= ~AC97_SR_CELV;
+            pRegs->sr &= ~SR_CELV;
             pRegs->civ = pRegs->piv;
-            pRegs->piv = (pRegs->piv + 1) % 32; /** @todo r=andy Define for max BDLEs? */
+            pRegs->piv = (pRegs->piv + 1) % 32;
 
-            ichac97StreamFetchBDLE(pThis, pStream);
+            ichac97StreamFetchBDLE(pThis, pStrmSt);
             continue;
         }
 
-        uint32_t cbToTransfer, cbTransferred;
-        switch (pStream->u8Strm)
+        uint32_t cbTransferred;
+        switch (enmSrc)
         {
-            case AC97SOUNDSOURCE_PO_INDEX:
+            case PO_INDEX:
             {
-                cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
-
-                rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred);
+                rc = ichac97WriteAudio(pThis, pStrmSt, cbElapsed, &cbTransferred);
                 if (   RT_SUCCESS(rc)
                     && cbTransferred)
                 {
-                    cbTotal     += cbTransferred;
-                    Assert(cbLeft >= cbTransferred);
-                    cbLeft      -= cbTransferred;
-                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
-                    pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
+                    cbWrittenTotal += cbTransferred;
+                    Assert(cbElapsed >= cbTransferred);
+                    cbElapsed      -= cbTransferred;
+                    Assert((cbTransferred & 1) == 0);    /* Else the following shift won't work */
+                    pRegs->picb    -= (cbTransferred >> 1);
                 }
                 break;
             }
 
-            case AC97SOUNDSOURCE_PI_INDEX:
-            case AC97SOUNDSOURCE_MC_INDEX:
+            case PI_INDEX:
+            case MC_INDEX:
             {
-                cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
-
-                rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
+                rc = ichac97ReadAudio(pThis, pStrmSt, cbElapsed, &cbTransferred);
                 if (   RT_SUCCESS(rc)
                     && cbTransferred)
                 {
-                    cbTotal     += cbTransferred;
-                    Assert(cbLeft >= cbTransferred);
-                    cbLeft      -= cbTransferred;
-                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
-                    pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
+                    Assert(cbElapsed >= cbTransferred);
+                    cbElapsed  -= cbTransferred;
+                    Assert((cbTransferred & 1) == 0);    /* Else the following shift won't work */
+                    pRegs->picb -= (cbTransferred >> 1);
                 }
                 break;
             }
 
             default:
-                AssertMsgFailed(("Stream #%RU8 not supported\n", pStream->u8Strm));
+                AssertMsgFailed(("Source %RU32 not supported\n", enmSrc));
                 rc = VERR_NOT_SUPPORTED;
                 break;
         }
 
-        LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8Strm, cbTotal, cbToProcess, rc));
+        LogFlowFunc(("pReg->picb=%#x, cbWrittenTotal=%RU32\n", pRegs->picb, cbWrittenTotal));
 
         if (!pRegs->picb)
         {
-            uint32_t new_sr = pRegs->sr & ~AC97_SR_CELV;
+            uint32_t new_sr = pRegs->sr & ~SR_CELV;
 
-            if (pRegs->bd.ctl_len & AC97_BD_IOC)
+            if (pRegs->bd.ctl_len & BD_IOC)
             {
-                new_sr |= AC97_SR_BCIS;
+                new_sr |= SR_BCIS;
             }
 
             if (pRegs->civ == pRegs->lvi)
             {
-                /* Did we run out of data? */
-                LogFunc(("Underrun CIV (%RU8) == LVI (%RU8)\n", pRegs->civ, pRegs->lvi));
-
-                new_sr |= AC97_SR_LVBCI | AC97_SR_DCH | AC97_SR_CELV;
-                pThis->bup_flag = (pRegs->bd.ctl_len & AC97_BD_BUP) ? BUP_LAST : 0;
+                LogFlowFunc(("Underrun civ (%RU8) == lvi (%RU8)\n", pRegs->civ, pRegs->lvi));
+                new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
+                pThis->bup_flag = (pRegs->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
 
                 rc = VINF_EOF;
             }
             else
             {
                 pRegs->civ = pRegs->piv;
-                pRegs->piv = (pRegs->piv + 1) % 32; /** @todo r=andy Define for max BDLEs? */
-                ichac97StreamFetchBDLE(pThis, pStream);
+                pRegs->piv = (pRegs->piv + 1) % 32;
+                ichac97StreamFetchBDLE(pThis, pStrmSt);
             }
 
-            ichac97StreamUpdateSR(pThis, pStream, new_sr);
+            ichac97StreamUpdateStatus(pThis, pStrmSt, new_sr);
         }
 
-        if (/* All data processed? */
-               rc == VINF_EOF
-            /* ... or an error occurred? */
-            || RT_FAILURE(rc))
+        if (   RT_FAILURE(rc)
+            || rc == VINF_EOF) /* All data processed? */
         {
             break;
         }
     }
 
-    int rc2 = RTCritSectLeave(&pStream->CritSect);
-    AssertRC(rc2);
-
-    if (RT_SUCCESS(rc))
-    {
-        if (pcbProcessed)
-            *pcbProcessed = cbTotal;
-    }
-
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -1740,26 +1426,17 @@ static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t
 /**
  * @callback_method_impl{FNIOMIOPORTIN}
  */
-static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32Val, unsigned cbVal)
+static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
+                                               uint32_t *pu32Val, unsigned cbVal)
 {
     RT_NOREF(pDevIns);
-    PAC97STATE pThis = (PAC97STATE)pvUser;
+    PAC97STATE pThis    = (PAC97STATE)pvUser;
 
     /* Get the index of the NABMBAR port. */
     const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
 
-    PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
-    PAC97BMREGS pRegs   = NULL;
-
-    if (pStream)
-    {
-        pRegs = &pStream->Regs;
-
-        int rc2 = RTCritSectEnter(&pStream->CritSect);
-        AssertRC(rc2);
-    }
-
-    int rc = VINF_SUCCESS;
+    PAC97STREAM pStrmSt     = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
+    PAC97BMREGS pRegs       = pStrmSt ? &pStrmSt->Regs : NULL;
 
     switch (cbVal)
     {
@@ -1767,9 +1444,9 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
         {
             switch (uPortIdx)
             {
-                case AC97_CAS:
+                case CAS:
                     /* Codec Access Semaphore Register */
-                    Log3Func(("CAS %d\n", pThis->cas));
+                    LogFlowFunc(("CAS %d\n", pThis->cas));
                     *pu32Val = pThis->cas;
                     pThis->cas = 1;
                     break;
@@ -1778,39 +1455,39 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
                 case MC_CIV:
                     /* Current Index Value Register */
                     *pu32Val = pRegs->civ;
-                    Log3Func(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 case PI_LVI:
                 case PO_LVI:
                 case MC_LVI:
                     /* Last Valid Index Register */
                     *pu32Val = pRegs->lvi;
-                    Log3Func(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 case PI_PIV:
                 case PO_PIV:
                 case MC_PIV:
                     /* Prefetched Index Value Register */
                     *pu32Val = pRegs->piv;
-                    Log3Func(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 case PI_CR:
                 case PO_CR:
                 case MC_CR:
                     /* Control Register */
                     *pu32Val = pRegs->cr;
-                    Log3Func(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 case PI_SR:
                 case PO_SR:
                 case MC_SR:
                     /* Status Register (lower part) */
-                    *pu32Val = RT_LO_U8(pRegs->sr);
-                    Log3Func(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    *pu32Val = pRegs->sr & 0xff; /** @todo r=andy Use RT_LO_U8. */
+                    LogFlowFunc(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 default:
                     *pu32Val = UINT32_MAX;
-                    LogFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
+                    LogFlowFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
                     break;
             }
             break;
@@ -1825,18 +1502,18 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
                 case MC_SR:
                     /* Status Register */
                     *pu32Val = pRegs->sr;
-                    Log3Func(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 case PI_PICB:
                 case PO_PICB:
                 case MC_PICB:
-                    /* Position in Current Buffer */
+                    /* Position in Current Buffer Register */
                     *pu32Val = pRegs->picb;
-                    Log3Func(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 default:
                     *pu32Val = UINT32_MAX;
-                    LogFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
+                    LogFlowFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
                     break;
             }
             break;
@@ -1851,7 +1528,7 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
                 case MC_BDBAR:
                     /* Buffer Descriptor Base Address Register */
                     *pu32Val = pRegs->bdbar;
-                    Log3Func(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+                    LogFlowFunc(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
                     break;
                 case PI_CIV:
                 case PO_CIV:
@@ -1860,8 +1537,8 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
                      *                Last Valid Index Register +
                      *                Status Register */
                     *pu32Val = pRegs->civ | (pRegs->lvi << 8) | (pRegs->sr << 16); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
-                    Log3Func(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
-                              AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
+                    LogFlowFunc(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
+                                 AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
                     break;
                 case PI_PICB:
                 case PO_PICB:
@@ -1870,41 +1547,31 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
                      *                Prefetched Index Value Register +
                      *                Control Register */
                     *pu32Val = pRegs->picb | (pRegs->piv << 16) | (pRegs->cr << 24); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
-                    Log3Func(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
-                              AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
+                    LogFlowFunc(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
+                                 AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
                     break;
-                case AC97_GLOB_CNT:
+                case GLOB_CNT:
                     /* Global Control */
                     *pu32Val = pThis->glob_cnt;
-                    Log3Func(("glob_cnt -> %#x\n", *pu32Val));
+                    LogFlowFunc(("glob_cnt -> %#x\n", *pu32Val));
                     break;
-                case AC97_GLOB_STA:
+                case GLOB_STA:
                     /* Global Status */
-                    *pu32Val = pThis->glob_sta | AC97_GS_S0CR;
-                    Log3Func(("glob_sta -> %#x\n", *pu32Val));
+                    *pu32Val = pThis->glob_sta | GS_S0CR;
+                    LogFlowFunc(("glob_sta -> %#x\n", *pu32Val));
                     break;
                 default:
                     *pu32Val = UINT32_MAX;
-                    LogFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
+                    LogFlowFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
                     break;
             }
             break;
         }
 
         default:
-        {
-            AssertFailed();
-            rc = VERR_IOM_IOPORT_UNUSED;
-        }
-    }
-
-    if (pStream)
-    {
-        int rc2 = RTCritSectLeave(&pStream->CritSect);
-        AssertRC(rc2);
+            return VERR_IOM_IOPORT_UNUSED;
     }
-
-    return rc;
+    return VINF_SUCCESS;
 }
 
 /**
@@ -1919,20 +1586,8 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
     /* Get the index of the NABMBAR register. */
     const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
 
-    PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
-    PAC97BMREGS pRegs   = NULL;
-
-    PAUDMIXSINK pSink   = NULL;
-
-    if (pStream)
-    {
-        pRegs = &pStream->Regs;
-        pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
-        AssertPtr(pSink);
-
-        int rc2 = RTCritSectEnter(&pStream->CritSect);
-        AssertRC(rc2);
-    }
+    PAC97STREAM pStrmSt     = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
+    PAC97BMREGS pRegs       = pStrmSt ? &pStrmSt->Regs : NULL;
 
     switch (cbVal)
     {
@@ -1940,79 +1595,62 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
         {
             switch (uPortIdx)
             {
-                /*
-                 * Last Valid Index.
-                 */
                 case PI_LVI:
                 case PO_LVI:
                 case MC_LVI:
-                {
-                    if (   (pRegs->cr & AC97_CR_RPBM)
-                        && (pRegs->sr & AC97_SR_DCH))
+                    /* Last Valid Index */
+                    if ((pRegs->cr & CR_RPBM) && (pRegs->sr & SR_DCH))
                     {
-                        pRegs->sr &= ~(AC97_SR_DCH | AC97_SR_CELV);
+                        pRegs->sr &= ~(SR_DCH | SR_CELV);
                         pRegs->civ = pRegs->piv;
                         pRegs->piv = (pRegs->piv + 1) % 32;
 
-                        ichac97StreamFetchBDLE(pThis, pStream);
+                        ichac97StreamFetchBDLE(pThis, pStrmSt);
                     }
                     pRegs->lvi = u32Val % 32;
-                    Log3Func(("[SD%RU8] LVI <- %#x\n", pStream->u8Strm, u32Val));
+                    LogFlowFunc(("LVI[%d] <- %#x\n", AC97_PORT2IDX(uPortIdx), u32Val));
                     break;
-                }
-
-                /*
-                 * Control Registers.
-                 */
                 case PI_CR:
                 case PO_CR:
                 case MC_CR:
                 {
-                    if (u32Val & AC97_CR_RR) /* Busmaster reset */
+                    /* Control Register */
+                    if (u32Val & CR_RR) /* Busmaster reset */
                     {
-                        ichac97StreamResetBMRegs(pThis, pStream);
+                        ichac97StreamResetBMRegs(pThis, pStrmSt);
                     }
                     else
                     {
-                        pRegs->cr = u32Val & AC97_CR_VALID_MASK;
-                        if (!(pRegs->cr & AC97_CR_RPBM))
+                        pRegs->cr = u32Val & CR_VALID_MASK;
+                        if (!(pRegs->cr & CR_RPBM))
                         {
-                            ichac97StreamEnable(pThis, pStream, false /* fActive */);
-
-                            pRegs->sr |= AC97_SR_DCH;
+                            ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
+                            pRegs->sr |= SR_DCH;
                         }
                         else
                         {
                             pRegs->civ = pRegs->piv;
                             pRegs->piv = (pRegs->piv + 1) % 32;
 
-                            pRegs->sr &= ~AC97_SR_DCH;
+                            ichac97StreamFetchBDLE(pThis, pStrmSt);
 
-                            /* Fetch the initial BDLE descriptor. */
-                            ichac97StreamFetchBDLE(pThis, pStream);
-
-                            ichac97StreamEnable(pThis, pStream, true /* fActive */);
+                            pRegs->sr &= ~SR_DCH;
+                            ichac97StreamSetActive(pThis, pStrmSt, true /* fActive */);
                         }
                     }
-                    Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr));
+                    LogFlowFunc(("CR[%d] <- %#x (cr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->cr));
                     break;
                 }
-
-                /*
-                 * Status Registers.
-                 */
                 case PI_SR:
                 case PO_SR:
                 case MC_SR:
-                {
-                    pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
-                    ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
-                    Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8Strm, u32Val, pRegs->sr));
+                    /* Status Register */
+                    pRegs->sr |= u32Val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+                    ichac97StreamUpdateStatus(pThis, pStrmSt, pRegs->sr & ~(u32Val & SR_WCLEAR_MASK));
+                    LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
                     break;
-                }
-
                 default:
-                    LogFunc(("Unimplemented: %#x <- %#x (Byte)\n", Port, u32Val));
+                    LogFlowFunc(("U nabm writeb %#x <- %#x\n", Port, u32Val));
                     break;
             }
             break;
@@ -2026,12 +1664,12 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
                 case PO_SR:
                 case MC_SR:
                     /* Status Register */
-                    pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
-                    ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
-                    Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8Strm, u32Val, pRegs->sr));
+                    pRegs->sr |= u32Val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+                    ichac97StreamUpdateStatus(pThis, pStrmSt, pRegs->sr & ~(u32Val & SR_WCLEAR_MASK));
+                    LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
                     break;
                 default:
-                    LogFunc(("Unimplemented: %#x <- %#x (Word)\n", Port, u32Val));
+                    LogFlowFunc(("U nabm writew %#x <- %#x\n", Port, u32Val));
                     break;
             }
             break;
@@ -2046,26 +1684,26 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
                 case MC_BDBAR:
                     /* Buffer Descriptor list Base Address Register */
                     pRegs->bdbar = u32Val & ~3;
-                    Log3Func(("[SD%RU8] BDBAR <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
+                    LogFlowFunc(("BDBAR[%d] <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
                     break;
-                case AC97_GLOB_CNT:
+                case GLOB_CNT:
                     /* Global Control */
-                    if (u32Val & AC97_GC_WR)
+                    if (u32Val & GC_WR)
                         ichac97WarmReset(pThis);
-                    if (u32Val & AC97_GC_CR)
+                    if (u32Val & GC_CR)
                         ichac97ColdReset(pThis);
-                    if (!(u32Val & (AC97_GC_WR | AC97_GC_CR)))
-                        pThis->glob_cnt = u32Val & AC97_GC_VALID_MASK;
-                    Log3Func(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
+                    if (!(u32Val & (GC_WR | GC_CR)))
+                        pThis->glob_cnt = u32Val & GC_VALID_MASK;
+                    LogFlowFunc(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
                     break;
-                case AC97_GLOB_STA:
+                case GLOB_STA:
                     /* Global Status */
-                    pThis->glob_sta &= ~(u32Val & AC97_GS_WCLEAR_MASK);
-                    pThis->glob_sta |= (u32Val & ~(AC97_GS_WCLEAR_MASK | AC97_GS_RO_MASK)) & AC97_GS_VALID_MASK;
-                    Log3Func(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
+                    pThis->glob_sta &= ~(u32Val & GS_WCLEAR_MASK);
+                    pThis->glob_sta |= (u32Val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
+                    LogFlowFunc(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
                     break;
                 default:
-                    LogFunc(("Unimplemented: %#x <- %#x (DWord)\n", Port, u32Val));
+                    LogFlowFunc(("U nabm writel %#x <- %#x\n", Port, u32Val));
                     break;
             }
             break;
@@ -2075,13 +1713,6 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
             break;
     }
-
-    if (pStream)
-    {
-        int rc2 = RTCritSectLeave(&pStream->CritSect);
-        AssertRC(rc2);
-    }
-
     return VINF_SUCCESS;
 }
 
@@ -2093,13 +1724,11 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser,
     RT_NOREF(pDevIns);
     PAC97STATE pThis = (PAC97STATE)pvUser;
 
-    int rc = VINF_SUCCESS;
-
     switch (cbVal)
     {
         case 1:
         {
-            Log3Func(("U nam readb %#x\n", Port));
+            LogFlowFunc(("U nam readb %#x\n", Port));
             pThis->cas = 0;
             *pu32Val = UINT32_MAX;
             break;
@@ -2114,7 +1743,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser,
             {
                 default:
                     *pu32Val = ichac97MixerGet(pThis, index);
-                    Log3Func(("nam readw %#x -> %#x\n", Port, *pu32Val));
+                    LogFlowFunc(("nam readw %#x -> %#x\n", Port, *pu32Val));
                     break;
             }
             break;
@@ -2122,20 +1751,16 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser,
 
         case 4:
         {
-            Log3Func(("U nam readl %#x\n", Port));
+            LogFlowFunc(("U nam readl %#x\n", Port));
             pThis->cas = 0;
             *pu32Val = UINT32_MAX;
             break;
         }
 
         default:
-        {
-            AssertFailed();
-            rc = VERR_IOM_IOPORT_UNUSED;
-        }
+            return VERR_IOM_IOPORT_UNUSED;
     }
-
-    return rc;
+    return VINF_SUCCESS;
 }
 
 /**
@@ -2150,7 +1775,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
     {
         case 1:
         {
-            Log3Func(("U nam writeb %#x <- %#x\n", Port, u32Val));
+            LogFlowFunc(("U nam writeb %#x <- %#x\n", Port, u32Val));
             pThis->cas = 0;
             break;
         }
@@ -2170,25 +1795,19 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
                     ichac97MixerSet(pThis, index, u32Val);
                     break;
                 case AC97_Master_Volume_Mute:
-                    if (pThis->uCodecModel == AC97_CODEC_AD1980)
-                    {
-                        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_LOSEL)
-                            break; /* Register controls surround (rear), do nothing. */
-                    }
-                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
+                    if (pThis->uCodecModel == Codec_AD1980)
+                        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_LOSEL)
+                            break;  /* Register controls surround (rear), do nothing. */
+                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
                     break;
                 case AC97_Headphone_Volume_Mute:
-                    if (pThis->uCodecModel == AC97_CODEC_AD1980)
-                    {
-                        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
-                        {
+                    if (pThis->uCodecModel == Codec_AD1980)
+                        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
                             /* Register controls PCM (front) outputs. */
-                            ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
-                        }
-                    }
+                            ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
                     break;
                 case AC97_PCM_Out_Volume_Mute:
-                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_FRONT, u32Val);
+                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_PCM, u32Val);
                     break;
                 case AC97_Line_In_Volume_Mute:
                     ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_LINE_IN, u32Val);
@@ -2198,60 +1817,60 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
                     break;
                 case AC97_Vendor_ID1:
                 case AC97_Vendor_ID2:
-                    LogFunc(("Attempt to write vendor ID to %#x\n", u32Val));
+                    LogFlowFunc(("Attempt to write vendor ID to %#x\n", u32Val));
                     break;
                 case AC97_Extended_Audio_ID:
-                    LogFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
+                    LogFlowFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
                     break;
                 case AC97_Extended_Audio_Ctrl_Stat:
-                    if (!(u32Val & AC97_EACS_VRA))
+                    if (!(u32Val & EACS_VRA))
                     {
                         ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000);
-                        ichac97StreamReOpen(pThis, &pThis->StreamOut);
+                        ichac97StreamReInit(pThis, &pThis->StrmStOut);
 
                         ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate,    48000);
-                        ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
+                        ichac97StreamReInit(pThis, &pThis->StrmStLineIn);
                     }
-                    if (!(u32Val & AC97_EACS_VRM))
+                    if (!(u32Val & EACS_VRM))
                     {
                         ichac97MixerSet(pThis, AC97_MIC_ADC_Rate,       48000);
-                        ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
+                        ichac97StreamReInit(pThis, &pThis->StrmStMicIn);
                     }
-                    LogFunc(("Setting extended audio control to %#x\n", u32Val));
+                    LogFlowFunc(("Setting extended audio control to %#x\n", u32Val));
                     ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val);
                     break;
                 case AC97_PCM_Front_DAC_Rate:
-                    if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
+                    if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
                     {
                         ichac97MixerSet(pThis, index, u32Val);
-                        LogFunc(("Set front DAC rate to %RU32\n", u32Val));
-                        ichac97StreamReOpen(pThis, &pThis->StreamOut);
+                        LogFlowFunc(("Set front DAC rate to %RU32\n", u32Val));
+                        ichac97StreamReInit(pThis, &pThis->StrmStOut);
                     }
                     else
-                        AssertMsgFailed(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
+                        LogFlowFunc(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
                     break;
                 case AC97_MIC_ADC_Rate:
-                    if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRM)
+                    if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM)
                     {
                         ichac97MixerSet(pThis, index, u32Val);
-                        LogFunc(("Set MIC ADC rate to %RU32\n", u32Val));
-                        ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
+                        LogFlowFunc(("Set MIC ADC rate to %RU32\n", u32Val));
+                        ichac97StreamReInit(pThis, &pThis->StrmStMicIn);
                     }
                     else
-                        AssertMsgFailed(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
+                        LogFlowFunc(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
                     break;
                 case AC97_PCM_LR_ADC_Rate:
-                    if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
+                    if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
                     {
                         ichac97MixerSet(pThis, index, u32Val);
-                        LogFunc(("Set front LR ADC rate to %RU32\n", u32Val));
-                        ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
+                        LogFlowFunc(("Set front LR ADC rate to %RU32\n", u32Val));
+                        ichac97StreamReInit(pThis, &pThis->StrmStLineIn);
                     }
                     else
-                        AssertMsgFailed(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
+                        LogFlowFunc(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
                     break;
                 default:
-                    LogFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
+                    LogFlowFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
                     ichac97MixerSet(pThis, index, u32Val);
                     break;
             }
@@ -2260,7 +1879,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
 
         case 4:
         {
-            Log3Func(("U nam writel %#x <- %#x\n", Port, u32Val));
+            LogFlowFunc(("U nam writel %#x <- %#x\n", Port, u32Val));
             pThis->cas = 0;
             break;
         }
@@ -2277,18 +1896,17 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int)
-ichac97IOPortMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ichac97IOPortMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                          RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
-    RT_NOREF(cb, enmType);
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
+    RT_NOREF(enmType, cb);
     PAC97STATE  pThis   = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
     RTIOPORT    Port    = (RTIOPORT)GCPhysAddress;
 
     Assert(enmType == PCI_ADDRESS_SPACE_IO);
     Assert(cb >= 0x20);
 
-    if (iRegion < 0 || iRegion > 1) /* We support 2 regions max. at the moment. */
+    if (iRegion > 1) /* We support 2 regions max. at the moment. */
         return VERR_INVALID_PARAMETER;
 
     int rc;
@@ -2311,20 +1929,20 @@ DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID)
 {
     switch (uID)
     {
-        case AC97SOUNDSOURCE_PI_INDEX: return &pThis->StreamLineIn;
-        case AC97SOUNDSOURCE_MC_INDEX: return &pThis->StreamMicIn;
-        case AC97SOUNDSOURCE_PO_INDEX: return &pThis->StreamOut;
-        default:                       break;
+        case PI_INDEX: return &pThis->StrmStLineIn;
+        case MC_INDEX: return &pThis->StrmStMicIn;
+        case PO_INDEX: return &pThis->StrmStOut;
+        default:       break;
     }
 
     return NULL;
 }
 
 #ifdef IN_RING3
-static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
+static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStrmSt)
 {
     RT_NOREF(pDevIns);
-    PAC97BMREGS pRegs = &pStream->Regs;
+    PAC97BMREGS pRegs = &pStrmSt->Regs;
 
     SSMR3PutU32(pSSM, pRegs->bdbar);
     SSMR3PutU8( pSSM, pRegs->civ);
@@ -2347,39 +1965,42 @@ static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
     PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
 
-    LogFlowFuncEnter();
-
     SSMR3PutU32(pSSM, pThis->glob_cnt);
     SSMR3PutU32(pSSM, pThis->glob_sta);
     SSMR3PutU32(pSSM, pThis->cas);
 
     /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
     /* Note: The order the streams are saved here is critical, so don't touch. */
-    int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamLineIn);
+    int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStLineIn);
     AssertRC(rc2);
-    rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamOut);
+    rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStOut);
     AssertRC(rc2);
-    rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamMicIn);
+    rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStMicIn);
     AssertRC(rc2);
 
     SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
 
-    uint8_t active[AC97SOUNDSOURCE_LAST_INDEX];
+    uint8_t active[LAST_INDEX];
 
-    active[AC97SOUNDSOURCE_PI_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamLineIn) ? 1 : 0;
-    active[AC97SOUNDSOURCE_PO_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamOut)    ? 1 : 0;
-    active[AC97SOUNDSOURCE_MC_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamMicIn)  ? 1 : 0;
+    PAC97DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+    {
+        PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
+        AssertPtr(pCon);
+        active[PI_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->LineIn.pStrmIn) ? 1 : 0;
+        active[PO_INDEX] = pCon->pfnIsActiveOut(pCon, pDrv->Out.pStrmOut)   ? 1 : 0;
+        active[MC_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->MicIn.pStrmIn)  ? 1 : 0;
+    }
 
     SSMR3PutMem(pSSM, active, sizeof(active));
 
-    LogFlowFuncLeaveRC(VINF_SUCCESS);
     return VINF_SUCCESS;
 }
 
-static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
+static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStrmSt)
 {
     RT_NOREF(pDevIns);
-    PAC97BMREGS pRegs = &pStream->Regs;
+    PAC97BMREGS pRegs = &pStrmSt->Regs;
 
     SSMR3GetU32(pSSM, &pRegs->bdbar);
     SSMR3GetU8( pSSM, &pRegs->civ);
@@ -2402,8 +2023,6 @@ static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, ui
 {
     PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
 
-    LogRel2(("ichac97LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
-
     AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
     Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
 
@@ -2413,43 +2032,47 @@ static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, ui
 
     /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
     /* Note: The order the streams are loaded here is critical, so don't touch. */
-    int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamLineIn);
+    int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStLineIn);
     AssertRC(rc2);
-    rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamOut);
+    rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStOut);
     AssertRC(rc2);
-    rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamMicIn);
+    rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStMicIn);
     AssertRC(rc2);
 
     SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
 
     /** @todo r=andy Stream IDs are hardcoded to certain streams. */
-    uint8_t uaStrmsActive[AC97SOUNDSOURCE_LAST_INDEX];
+    uint8_t uaStrmsActive[LAST_INDEX];
     SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
 
     ichac97RecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
 # define V_(a, b) ichac97MixerSetVolume(pThis, a, b, ichac97MixerGet(pThis, a))
-    V_(AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME_MASTER);
-    V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
+    V_(AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME);
+    V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM);
     V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
-    V_(AC97_Mic_Volume_Mute,     PDMAUDIOMIXERCTL_MIC_IN);
 # undef V_
-    if (pThis->uCodecModel == AC97_CODEC_AD1980)
-        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
-            ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
+    if (pThis->uCodecModel == Codec_AD1980)
+        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
+            ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME,
                              ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
 
-    rc2 = ichac97StreamsInit(pThis);
-    if (RT_SUCCESS(rc2))
-    {
-        /** @todo r=andy Stream IDs are hardcoded to certain streams. */
-        rc2 = ichac97StreamEnable(pThis, &pThis->StreamLineIn,    RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PI_INDEX]));
-        if (RT_SUCCESS(rc2))
-            rc2 = ichac97StreamEnable(pThis, &pThis->StreamMicIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_MC_INDEX]));
-        if (RT_SUCCESS(rc2))
-            rc2 = ichac97StreamEnable(pThis, &pThis->StreamOut,   RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PO_INDEX]));
-    }
+    int rc;
+    rc = ichac97StreamInit(pThis, &pThis->StrmStLineIn, PI_INDEX);
+    AssertRC(rc);
+    rc = ichac97StreamInit(pThis, &pThis->StrmStMicIn,  MC_INDEX);
+    AssertRC(rc);
+    rc = ichac97StreamInit(pThis, &pThis->StrmStOut,    PO_INDEX);
+    AssertRC(rc);
 
-    pThis->bup_flag  = 0;
+    /** @todo r=andy Stream IDs are hardcoded to certain streams. */
+    rc = ichac97StreamSetActive(pThis, &pThis->StrmStLineIn, RT_BOOL(uaStrmsActive[PI_INDEX]));
+    AssertRC(rc);
+    rc = ichac97StreamSetActive(pThis, &pThis->StrmStMicIn,  RT_BOOL(uaStrmsActive[MC_INDEX]));
+    AssertRC(rc);
+    rc = ichac97StreamSetActive(pThis, &pThis->StrmStOut,    RT_BOOL(uaStrmsActive[PO_INDEX]));
+    AssertRC(rc);
+
+    pThis->bup_flag = 0;
     pThis->last_samp = 0;
 
     return VINF_SUCCESS;
@@ -2470,30 +2093,6 @@ static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, c
 
 
 /**
- * Powers off the device.
- *
- * @param   pDevIns             Device instance to power off.
- */
-static DECLCALLBACK(void) ichac97PowerOff(PPDMDEVINS pDevIns)
-{
-    PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
-    LogRel2(("AC97: Powering off ...\n"));
-
-    /**
-     * Note: Destroy the mixer while powering off and *not* in ichac97Destruct,
-     *       giving the mixer the chance to release any references held to
-     *       PDM audio streams it maintains.
-     */
-    if (pThis->pMixer)
-    {
-        AudioMixerDestroy(pThis->pMixer);
-        pThis->pMixer = NULL;
-    }
-}
-
-
-/**
  * @interface_method_impl{PDMDEVREG,pfnReset}
  *
  * @remarks The original sources didn't install a reset handler, but it seems to
@@ -2508,9 +2107,9 @@ static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
     /*
      * Reset the device state (will need pDrv later).
      */
-    ichac97StreamResetBMRegs(pThis, &pThis->StreamLineIn);
-    ichac97StreamResetBMRegs(pThis, &pThis->StreamMicIn);
-    ichac97StreamResetBMRegs(pThis, &pThis->StreamOut);
+    ichac97StreamResetBMRegs(pThis, &pThis->StrmStLineIn);
+    ichac97StreamResetBMRegs(pThis, &pThis->StrmStMicIn);
+    ichac97StreamResetBMRegs(pThis, &pThis->StrmStOut);
 
     /*
      * Reset the mixer too. The Windows XP driver seems to rely on
@@ -2520,11 +2119,25 @@ static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
     ichac97MixerReset(pThis);
 
     /*
+     * Stop any audio currently playing.
+     */
+    PAC97DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+    {
+        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,  pDrv->LineIn.pStrmIn, false /* Disable */);
+        /* Ignore rc. */
+        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,  pDrv->MicIn.pStrmIn,  false /* Disable */);
+        /* Ditto. */
+        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut,   false /* Disable */);
+        /* Ditto. */
+    }
+
+    /*
      * Reset all streams.
      */
-    ichac97StreamReset(pThis, &pThis->StreamLineIn);
-    ichac97StreamReset(pThis, &pThis->StreamMicIn);
-    ichac97StreamReset(pThis, &pThis->StreamOut);
+    ichac97StreamReset(pThis, &pThis->StrmStLineIn);
+    ichac97StreamReset(pThis, &pThis->StrmStMicIn);
+    ichac97StreamReset(pThis, &pThis->StrmStOut);
 
     LogRel(("AC97: Reset\n"));
 }
@@ -2535,33 +2148,35 @@ static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
  */
 static DECLCALLBACK(int) ichac97Destruct(PPDMDEVINS pDevIns)
 {
+    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
     PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
 
     LogFlowFuncEnter();
 
-    ichac97StreamDestroy(&pThis->StreamLineIn);
-    ichac97StreamDestroy(&pThis->StreamMicIn);
-    ichac97StreamDestroy(&pThis->StreamOut);
-
-    PAC97DRIVER pDrv, pDrvNext;
-    RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, AC97DRIVER, Node)
+    PAC97DRIVER pDrv;
+    while (!RTListIsEmpty(&pThis->lstDrv))
     {
+        pDrv = RTListGetFirst(&pThis->lstDrv, AC97DRIVER, Node);
+
         RTListNodeRemove(&pDrv->Node);
         RTMemFree(pDrv);
     }
 
-    /* Sanity. */
-    Assert(RTListIsEmpty(&pThis->lstDrv));
+    if (pThis->pMixer)
+    {
+        AudioMixerDestroy(pThis->pMixer);
+        pThis->pMixer = NULL;
+    }
 
-    int rc;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-    rc = RTCritSectDelete(&pThis->csTimer);
-#else
-    rc = VINF_SUCCESS;
-#endif
+    if (pThis->pvReadWriteBuf)
+    {
+        RTMemFree(pThis->pvReadWriteBuf);
+        pThis->pvReadWriteBuf = NULL;
+        pThis->cbReadWriteBuf = 0;
+    }
 
-    LogFlowFuncLeaveRC(rc);
-    return rc;
+    LogFlowFuncLeave();
+    return VINF_SUCCESS;
 }
 
 
@@ -2614,7 +2229,7 @@ static DECLCALLBACK(int) ichac97AttachInternal(PPDMDEVINS pDevIns, PAC97DRIVER p
              * host backend. This might change in the future.
              */
             if (pDrv->uLUN == 0)
-                pDrv->Flags |= PDMAUDIODRVFLAGS_PRIMARY;
+                pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
 
             LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
 
@@ -2699,7 +2314,7 @@ static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, con
 
 #define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
 
-    int rc;
+    int rc = VINF_SUCCESS;
     do
     {
         PCFGMNODE pLunL0;
@@ -2732,13 +2347,14 @@ static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, con
 static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
 {
     RT_NOREF(iInstance);
+    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+
     PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
 
     /* NB: This must be done *before* any possible failure (and running the destructor). */
     RTListInit(&pThis->lstDrv);
 
     Assert(iInstance == 0);
-    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
 
     /*
      * Validations.
@@ -2760,7 +2376,7 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
 
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     uint16_t uTimerHz;
-    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, AC97_TIMER_HZ /* Default value, if not set. */);
+    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("AC'97 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
@@ -2772,11 +2388,11 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
      * 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
      */
     if (!strcmp(szCodec, "STAC9700"))
-        pThis->uCodecModel = AC97_CODEC_STAC9700;
+        pThis->uCodecModel = Codec_STAC9700;
     else if (!strcmp(szCodec, "AD1980"))
-        pThis->uCodecModel = AC97_CODEC_AD1980;
+        pThis->uCodecModel = Codec_AD1980;
     else if (!strcmp(szCodec, "AD1981B"))
-        pThis->uCodecModel = AC97_CODEC_AD1981B;
+        pThis->uCodecModel = Codec_AD1981B;
     else
     {
         return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
@@ -2792,28 +2408,28 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
     pThis->IBase.pfnQueryInterface  = ichac97QueryInterface;
 
     /* PCI Device (the assertions will be removed later) */
-    PCIDevSetVendorId         (&pThis->PciDev, 0x8086); /* 00 ro - intel. */               Assert(pThis->PciDev.config[0x00] == 0x86); Assert(pThis->PciDev.config[0x01] == 0x80);
-    PCIDevSetDeviceId         (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */  Assert(pThis->PciDev.config[0x02] == 0x15); Assert(pThis->PciDev.config[0x03] == 0x24);
-    PCIDevSetCommand          (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */           Assert(pThis->PciDev.config[0x04] == 0x00); Assert(pThis->PciDev.config[0x05] == 0x00);
-    PCIDevSetStatus           (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM |  VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */      Assert(pThis->PciDev.config[0x06] == 0x80); Assert(pThis->PciDev.config[0x07] == 0x02);
-    PCIDevSetRevisionId       (&pThis->PciDev, 0x01);   /* 08 ro - rid. */                 Assert(pThis->PciDev.config[0x08] == 0x01);
-    PCIDevSetClassProg        (&pThis->PciDev, 0x00);   /* 09 ro - pi. */                  Assert(pThis->PciDev.config[0x09] == 0x00);
-    PCIDevSetClassSub         (&pThis->PciDev, 0x01);   /* 0a ro - scc; 01 == Audio. */    Assert(pThis->PciDev.config[0x0a] == 0x01);
-    PCIDevSetClassBase        (&pThis->PciDev, 0x04);   /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.config[0x0b] == 0x04);
-    PCIDevSetHeaderType       (&pThis->PciDev, 0x00);   /* 0e ro - headtyp. */             Assert(pThis->PciDev.config[0x0e] == 0x00);
+    PCIDevSetVendorId         (&pThis->PciDev, 0x8086); /* 00 ro - intel. */               Assert(pThis->PciDev.abConfig[0x00] == 0x86); Assert(pThis->PciDev.abConfig[0x01] == 0x80);
+    PCIDevSetDeviceId         (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */  Assert(pThis->PciDev.abConfig[0x02] == 0x15); Assert(pThis->PciDev.abConfig[0x03] == 0x24);
+    PCIDevSetCommand          (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */           Assert(pThis->PciDev.abConfig[0x04] == 0x00); Assert(pThis->PciDev.abConfig[0x05] == 0x00);
+    PCIDevSetStatus           (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM |  VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */      Assert(pThis->PciDev.abConfig[0x06] == 0x80); Assert(pThis->PciDev.abConfig[0x07] == 0x02);
+    PCIDevSetRevisionId       (&pThis->PciDev, 0x01);   /* 08 ro - rid. */                 Assert(pThis->PciDev.abConfig[0x08] == 0x01);
+    PCIDevSetClassProg        (&pThis->PciDev, 0x00);   /* 09 ro - pi. */                  Assert(pThis->PciDev.abConfig[0x09] == 0x00);
+    PCIDevSetClassSub         (&pThis->PciDev, 0x01);   /* 0a ro - scc; 01 == Audio. */    Assert(pThis->PciDev.abConfig[0x0a] == 0x01);
+    PCIDevSetClassBase        (&pThis->PciDev, 0x04);   /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.abConfig[0x0b] == 0x04);
+    PCIDevSetHeaderType       (&pThis->PciDev, 0x00);   /* 0e ro - headtyp. */             Assert(pThis->PciDev.abConfig[0x0e] == 0x00);
     PCIDevSetBaseAddress      (&pThis->PciDev, 0,       /* 10 rw - nambar - native audio mixer base. */
-                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.config[0x10] == 0x01); Assert(pThis->PciDev.config[0x11] == 0x00); Assert(pThis->PciDev.config[0x12] == 0x00); Assert(pThis->PciDev.config[0x13] == 0x00);
+                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x10] == 0x01); Assert(pThis->PciDev.abConfig[0x11] == 0x00); Assert(pThis->PciDev.abConfig[0x12] == 0x00); Assert(pThis->PciDev.abConfig[0x13] == 0x00);
     PCIDevSetBaseAddress      (&pThis->PciDev, 1,       /* 14 rw - nabmbar - native audio bus mastering. */
-                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.config[0x14] == 0x01); Assert(pThis->PciDev.config[0x15] == 0x00); Assert(pThis->PciDev.config[0x16] == 0x00); Assert(pThis->PciDev.config[0x17] == 0x00);
-    PCIDevSetInterruptLine    (&pThis->PciDev, 0x00);   /* 3c rw. */                       Assert(pThis->PciDev.config[0x3c] == 0x00);
-    PCIDevSetInterruptPin     (&pThis->PciDev, 0x01);   /* 3d ro - INTA#. */               Assert(pThis->PciDev.config[0x3d] == 0x01);
+                               true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x14] == 0x01); Assert(pThis->PciDev.abConfig[0x15] == 0x00); Assert(pThis->PciDev.abConfig[0x16] == 0x00); Assert(pThis->PciDev.abConfig[0x17] == 0x00);
+    PCIDevSetInterruptLine    (&pThis->PciDev, 0x00);   /* 3c rw. */                       Assert(pThis->PciDev.abConfig[0x3c] == 0x00);
+    PCIDevSetInterruptPin     (&pThis->PciDev, 0x01);   /* 3d ro - INTA#. */               Assert(pThis->PciDev.abConfig[0x3d] == 0x01);
 
-    if (pThis->uCodecModel == AC97_CODEC_AD1980)
+    if (pThis->uCodecModel == Codec_AD1980)
     {
         PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
         PCIDevSetSubSystemId      (&pThis->PciDev, 0x0177); /* 2e ro. */
     }
-    else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
+    else if (pThis->uCodecModel == Codec_AD1981B)
     {
         PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
         PCIDevSetSubSystemId      (&pThis->PciDev, 0x01ad); /* 2e ro. */
@@ -2876,15 +2492,25 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
         rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThis->pMixer);
         if (RT_SUCCESS(rc))
         {
+            /* Set a default audio format for our mixer. */
+            PDMAUDIOSTREAMCFG streamCfg;
+            streamCfg.uHz           = 44100;
+            streamCfg.cChannels     = 2;
+            streamCfg.enmFormat     = AUD_FMT_S16;
+            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+            rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
+            AssertRC(rc);
+
             /* Add all required audio sinks. */
-            int rc2 = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOut);
-            AssertRC(rc2);
+            rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
+            AssertRC(rc);
 
-            rc2 = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
-            AssertRC(rc2);
+            rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
+            AssertRC(rc);
 
-            rc2 = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
-            AssertRC(rc2);
+            rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
+            AssertRC(rc);
         }
     }
 
@@ -2892,7 +2518,15 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
 
     if (RT_SUCCESS(rc))
     {
-        ichac97StreamsInit(pThis);
+        rc = ichac97StreamInit(pThis, &pThis->StrmStLineIn, PI_INDEX);
+        if (RT_FAILURE(rc))
+            return rc;
+        rc = ichac97StreamInit(pThis, &pThis->StrmStMicIn,  MC_INDEX);
+        if (RT_FAILURE(rc))
+            return rc;
+        rc = ichac97StreamInit(pThis, &pThis->StrmStOut,    PO_INDEX);
+        if (RT_FAILURE(rc))
+            return rc;
 
         PAC97DRIVER pDrv;
         RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
@@ -2901,15 +2535,15 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
              * Only primary drivers are critical for the VM to run. Everything else
              * might not worth showing an own error message box in the GUI.
              */
-            if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+            if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
                 continue;
 
             PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
             AssertPtr(pCon);
 
-            bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
-            bool fValidMicIn  = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
-            bool fValidOut    = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
+            bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
+            bool fValidMicIn  = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
+            bool fValidOut    = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
 
             if (    !fValidLineIn
                  && !fValidMicIn
@@ -2917,14 +2551,9 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
             {
                 LogRel(("AC97: Falling back to NULL backend (no sound audible)\n"));
 
-                /* Destroy the streams before re-attaching the NULL driver. */
-                ichac97StreamsDestroy(pThis);
-
                 ichac97Reset(pDevIns);
                 ichac97Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
 
-                ichac97StreamsInit(pThis);
-
                 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
                     N_("No audio devices could be opened. Selecting the NULL audio backend "
                        "with the consequence that no sound is audible"));
@@ -2934,38 +2563,36 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
                 bool fWarn = false;
 
                 PDMAUDIOBACKENDCFG backendCfg;
-                int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
+                int rc2 = pCon->pfnGetConfiguration(pCon, &backendCfg);
                 if (RT_SUCCESS(rc2))
                 {
-                    if (backendCfg.cSources)
+                    if (backendCfg.cMaxHstStrmsIn)
                     {
                         /* If the audio backend supports two or more input streams at once,
                          * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
-                        if (backendCfg.cMaxStreamsIn >= 2)
+                        if (backendCfg.cMaxHstStrmsIn >= 2)
                             fWarn = !fValidLineIn || !fValidMicIn;
                         /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
                          * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
                          * One of the two simply is not in use then. */
-                        else if (backendCfg.cMaxStreamsIn == 1)
+                        else if (backendCfg.cMaxHstStrmsIn == 1)
                             fWarn = !fValidLineIn && !fValidMicIn;
                         /* Don't warn if our backend is not able of supporting any input streams at all. */
                     }
 
                     if (   !fWarn
-                        && backendCfg.cSinks)
+                        && backendCfg.cMaxHstStrmsOut)
                     {
                         fWarn = !fValidOut;
                     }
                 }
                 else
-                {
-                    LogRel(("AC97: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
-                    fWarn = true;
-                }
+                    AssertReleaseMsgFailed(("Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n",
+                                            pDrv->uLUN, rc2));
 
                 if (fWarn)
                 {
-                    char   szMissingStreams[255] = "";
+                    char   szMissingStreams[255];
                     size_t len = 0;
                     if (!fValidLineIn)
                     {
@@ -2995,23 +2622,30 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
         }
     }
 
+    if (RT_SUCCESS(rc))
+    {
+        pThis->cbReadWriteBuf = _4K; /** @todo Make this configurable. */
+        pThis->pvReadWriteBuf = (uint8_t *)RTMemAllocZ(pThis->cbReadWriteBuf);
+        if (!pThis->pvReadWriteBuf)
+            rc = VERR_NO_MEMORY;
+    }
+
 # ifndef VBOX_WITH_AUDIO_CALLBACKS
     if (RT_SUCCESS(rc))
     {
-        rc = RTCritSectInit(&pThis->csTimer);
+        /* Start the emulation timer. */
+        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
+                                    TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
+        AssertRCReturn(rc, rc);
+
         if (RT_SUCCESS(rc))
         {
-            /* Start the emulation timer. */
-            rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
-                                        TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
-            AssertRCReturn(rc, rc);
+            pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
+            pThis->uTimerTS    = TMTimerGet(pThis->pTimer);
+            LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
 
-            if (RT_SUCCESS(rc))
-            {
-                pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
-                pThis->uTimerTS    = TMTimerGet(pThis->pTimer);
-                LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
-            }
+            /* Fire off timer. */
+            TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
         }
     }
 # else
@@ -3022,7 +2656,7 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
         {
             /* Only register primary driver.
              * The device emulation does the output multiplexing then. */
-            if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+            if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
                 continue;
 
             PDMAUDIOCALLBACK AudioCallbacks[2];
@@ -3110,7 +2744,7 @@ const PDMDEVREG g_DeviceICHAC97 =
     /* pfnInitComplete */
     NULL,
     /* pfnPowerOff */
-    ichac97PowerOff,
+    NULL,
     /* pfnSoftReset */
     NULL,
     /* u32VersionEnd */
diff --git a/src/VBox/Devices/Audio/DevIchHdaCodec.h b/src/VBox/Devices/Audio_50/DevIchHdaCodec.h
similarity index 68%
rename from src/VBox/Devices/Audio/DevIchHdaCodec.h
rename to src/VBox/Devices/Audio_50/DevIchHdaCodec.h
index 2e1a997..825a553 100644
--- a/src/VBox/Devices/Audio/DevIchHdaCodec.h
+++ b/src/VBox/Devices/Audio_50/DevIchHdaCodec.h
@@ -15,8 +15,8 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
 
-#ifndef DEV_HDA_CODEC_H
-#define DEV_HDA_CODEC_H
+#ifndef DEV_CODEC_H
+#define DEV_CODEC_H
 
 /** The ICH HDA (Intel) controller. */
 typedef struct HDASTATE *PHDASTATE;
@@ -38,24 +38,36 @@ typedef FNHDACODECVERBPROCESSOR **PPFNHDACODECVERBPROCESSOR;
 /* PRM 5.3.1 */
 #define CODEC_RESPONSE_UNSOLICITED RT_BIT_64(34)
 
+
+#ifndef VBOX_WITH_HDA_CODEC_EMU
 typedef struct CODECVERB
 {
-    /** Verb. */
-    uint32_t                 verb;
-    /** Verb mask. */
-    uint32_t                 mask;
-    /** Function pointer for implementation callback. */
+    uint32_t verb;
+    /** operation bitness mask */
+    uint32_t mask;
     PFNHDACODECVERBPROCESSOR pfn;
-    /** Friendly name, for debugging. */
-    const char              *pszName;
 } CODECVERB;
+#endif
+
+#ifndef VBOX_WITH_HDA_CODEC_EMU
+# define TYPE union
+#else
+# define TYPE struct
+typedef struct CODECEMU CODECEMU;
+typedef CODECEMU *PCODECEMU;
+#endif
+TYPE CODECNODE;
+typedef TYPE CODECNODE CODECNODE;
+typedef TYPE CODECNODE *PCODECNODE;
+
+typedef enum
+{
+    PI_INDEX = 0,    /**< PCM in */
+    PO_INDEX,        /**< PCM out */
+    MC_INDEX,        /**< Mic in */
+    LAST_INDEX
+} ENMSOUNDSOURCE;
 
-union CODECNODE;
-typedef union CODECNODE CODECNODE, *PCODECNODE;
-
-/**
- * Structure for keeping a HDA codec state.
- */
 typedef struct HDACODEC
 {
     uint16_t                id;
@@ -66,16 +78,21 @@ typedef struct HDACODEC
     /** List of assigned HDA drivers to this codec.
      * A driver only can be assigned to one codec at a time. */
     RTLISTANCHOR            lstDrv;
+    /** The codec's current audio stream configuration. */
+    PDMAUDIOSTREAMCFG       strmCfg;
 
+#ifndef VBOX_WITH_HDA_CODEC_EMU
     CODECVERB const        *paVerbs;
-    size_t                  cVerbs;
-
+    int                     cVerbs;
+#else
+    PCODECEMU               pCodecBackend;
+#endif
     PCODECNODE              paNodes;
     /** Pointer to HDA state (controller) this
      *  codec is assigned to. */
     PHDASTATE               pHDAState;
     bool                    fInReset;
-
+#ifndef VBOX_WITH_HDA_CODEC_EMU
     const uint8_t           cTotalNodes;
     const uint8_t          *au8Ports;
     const uint8_t          *au8Dacs;
@@ -92,14 +109,15 @@ typedef struct HDACODEC
     const uint8_t          *au8Reserveds;
     const uint8_t           u8AdcVolsLineIn;
     const uint8_t           u8DacLineOut;
-
+#endif
     /** Callbacks to the HDA controller, mostly used for multiplexing to the various host backends. */
-    DECLR3CALLBACKMEMBER(int, pfnMixerAddStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg));
-    DECLR3CALLBACKMEMBER(int, pfnMixerRemoveStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl));
-    DECLR3CALLBACKMEMBER(int, pfnMixerSetStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel));
-    DECLR3CALLBACKMEMBER(int, pfnMixerSetVolume, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol));
+    DECLR3CALLBACKMEMBER(void, pfnCloseIn, (PHDASTATE pThis, PDMAUDIORECSOURCE enmRecSource));
+    DECLR3CALLBACKMEMBER(void, pfnCloseOut, (PHDASTATE pThis));
+    DECLR3CALLBACKMEMBER(int, pfnOpenIn, (PHDASTATE pThis, const char *pszName, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg));
+    DECLR3CALLBACKMEMBER(int, pfnOpenOut, (PHDASTATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg));
+    DECLR3CALLBACKMEMBER(int, pfnSetVolume, (PHDASTATE pThis, ENMSOUNDSOURCE enmSource, bool fMute, uint8_t uVolLeft, uint8_t uVolRight));
     /** Callbacks by codec implementation. */
-    DECLR3CALLBACKMEMBER(int, pfnLookup, (PHDACODEC pThis, uint32_t uVerb, uint64_t *puResp));
+    DECLR3CALLBACKMEMBER(int, pfnLookup, (PHDACODEC pThis, uint32_t verb, PPFNHDACODECVERBPROCESSOR));
     DECLR3CALLBACKMEMBER(int, pfnReset, (PHDACODEC pThis));
     DECLR3CALLBACKMEMBER(int, pfnCodecNodeReset, (PHDACODEC pThis, uint8_t, PCODECNODE));
     /** These callbacks are set by codec implementation to answer debugger requests. */
@@ -108,12 +126,10 @@ typedef struct HDACODEC
 } HDACODEC;
 
 int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, uint16_t uLUN, PCFGMNODE pCfg);
-void hdaCodecDestruct(PHDACODEC pThis);
-void hdaCodecPowerOff(PHDACODEC pThis);
+int hdaCodecDestruct(PHDACODEC pThis);
 int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM);
 int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion);
-int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg);
-int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl);
+int hdaCodecOpenStream(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, PPDMAUDIOSTREAMCFG pCfg);
 
 #define HDA_SSM_VERSION   6
 /** Introduced dynamic number of streams + stream identifiers for serialization.
@@ -126,5 +142,14 @@ int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl);
 #define HDA_SSM_VERSION_2 2
 #define HDA_SSM_VERSION_1 1
 
-#endif /* DEV_HDA_CODEC_H */
+# ifdef VBOX_WITH_HDA_CODEC_EMU
+/* */
+struct CODECEMU
+{
+    DECLR3CALLBACKMEMBER(int, pfnCodecEmuConstruct,(PHDACODEC pThis));
+    DECLR3CALLBACKMEMBER(int, pfnCodecEmuDestruct,(PHDACODEC pThis));
+    DECLR3CALLBACKMEMBER(int, pfnCodecEmuReset,(PHDACODEC pThis, bool fInit));
+};
+# endif
+#endif
 
diff --git a/src/VBox/Devices/Audio_50/DevSB16.cpp b/src/VBox/Devices/Audio_50/DevSB16.cpp
new file mode 100644
index 0000000..25658f9
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DevSB16.cpp
@@ -0,0 +1,2449 @@
+/* $Id: DevSB16.cpp $ */
+/** @file
+ * DevSB16 - VBox SB16 Audio Controller.
+ *
+ * @todo hiccups on NT4 and Win98.
+ */
+
+/*
+ * Copyright (C) 2015-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: sb16.c from QEMU AUDIO subsystem (r3917).
+ * QEMU Soundblaster 16 emulation
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define LOG_GROUP LOG_GROUP_DEV_SB16
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#ifdef IN_RING3
+# include <iprt/mem.h>
+# include <iprt/string.h>
+# include <iprt/uuid.h>
+#endif
+
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+#include "VBoxDD.h"
+
+#include "AudioMixBuffer.h"
+#include "AudioMixer.h"
+#include "DrvAudio.h"
+
+/** Current saved state version. */
+#define SB16_SAVE_STATE_VERSION         2
+/** The version used in VirtualBox version 3.0 and earlier. This didn't include the config dump. */
+#define SB16_SAVE_STATE_VERSION_VBOX_30 1
+
+#define IO_READ_PROTO(name)                                             \
+    DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque,       \
+                            RTIOPORT nport, uint32_t *pu32, unsigned cb)
+
+#define IO_WRITE_PROTO(name)                                            \
+    DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque,       \
+                            RTIOPORT nport, uint32_t val, unsigned cb)
+
+static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
+
+typedef struct SB16OUTPUTSTREAM
+{
+    /** PCM output stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
+    /** Mixer handle for output stream. */
+    R3PTRTYPE(PAUDMIXSTREAM)           phStrmOut;
+} SB16OUTPUTSTREAM, *PSB16OUTPUTSTREAM;
+
+/**
+ * Struct for maintaining a host backend driver.
+ */
+typedef struct SB16STATE *PSB16STATE;
+typedef struct SB16DRIVER
+{
+    /** Node for storing this driver in our device driver list of SB16STATE. */
+    RTLISTNODER3                       Node;
+    /** Pointer to SB16 controller (state). */
+    R3PTRTYPE(PSB16STATE)              pSB16State;
+    /** Driver flags. */
+    PDMAUDIODRVFLAGS                   Flags;
+    uint32_t                           PaddingFlags;
+    /** LUN # to which this driver has been assigned. */
+    uint8_t                            uLUN;
+    /** Whether this driver is in an attached state or not. */
+    bool                               fAttached;
+    uint8_t                            Padding[4];
+    /** Pointer to attached driver base interface. */
+    R3PTRTYPE(PPDMIBASE)               pDrvBase;
+    /** Audio connector interface to the underlying host backend. */
+    R3PTRTYPE(PPDMIAUDIOCONNECTOR)     pConnector;
+    /** Stream for output. */
+    SB16OUTPUTSTREAM                   Out;
+} SB16DRIVER, *PSB16DRIVER;
+
+typedef struct SB16STATE
+{
+#ifdef VBOX
+    /** Pointer to the device instance. */
+    PPDMDEVINSR3        pDevInsR3;
+    /** Pointer to the connector of the attached audio driver. */
+    PPDMIAUDIOCONNECTOR pDrv;
+    int irqCfg;
+    int dmaCfg;
+    int hdmaCfg;
+    int portCfg;
+    int verCfg;
+#endif
+    int irq;
+    int dma;
+    int hdma;
+    int port;
+    int ver;
+
+    int in_index;
+    int out_data_len;
+    int fmt_stereo;
+    int fmt_signed;
+    int fmt_bits;
+    PDMAUDIOFMT fmt;
+    int dma_auto;
+    int block_size;
+    int fifo;
+    int freq;
+    int time_const;
+    int speaker;
+    int needed_bytes;
+    int cmd;
+    int use_hdma;
+    int highspeed;
+    int can_write; /** @todo Value never gets 0? */
+
+    int v2x6;
+
+    uint8_t csp_param;
+    uint8_t csp_value;
+    uint8_t csp_mode;
+    uint8_t csp_regs[256];
+    uint8_t csp_index;
+    uint8_t csp_reg83[4];
+    int csp_reg83r;
+    int csp_reg83w;
+
+    uint8_t in2_data[10];
+    uint8_t out_data[50];
+    uint8_t test_reg;
+    uint8_t last_read_byte;
+    int nzero;
+
+    int left_till_irq; /** Note: Can be < 0. */
+
+    int dma_running;
+    int bytes_per_second;
+    int align;
+
+    RTLISTANCHOR                   lstDrv;
+    /** The device' software mixer. */
+    R3PTRTYPE(PAUDIOMIXER)         pMixer;
+    /** Audio sink for PCM output. */
+    R3PTRTYPE(PAUDMIXSINK)         pSinkOutput;
+#ifndef VBOX_WITH_AUDIO_CALLBACKS
+    /** The timer for pumping data thru the attached LUN drivers. */
+    PTMTIMERR3                     pTimerIO;
+    /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
+    uint64_t                       cTimerTicksIO;
+    /** Timestamp of the last timer callback (sb16TimerIO).
+     * Used to calculate the time actually elapsed between two timer callbacks. */
+    uint64_t                       uTimerTSIO;
+#endif
+    PTMTIMER                       pTimerIRQ;
+    /** The base interface for LUN\#0. */
+    PDMIBASE                       IBase;
+
+    /* mixer state */
+    int mixer_nreg;
+    uint8_t mixer_regs[256];
+} SB16STATE, *PSB16STATE;
+
+static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
+
+/**
+ * Attach command, internal version.
+ *
+ * This is called to let the device attach to a driver for a specified LUN
+ * during runtime. This is not called during VM construction, the device
+ * constructor has to attach to all the available drivers.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns     The device instance.
+ * @param   pDrv        Driver to (re-)use for (re-)attaching to.
+ *                      If NULL is specified, a new driver will be created and appended
+ *                      to the driver list.
+ * @param   uLUN        The logical unit which is being detached.
+ * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
+ */
+static DECLCALLBACK(int) sb16AttachInternal(PPDMDEVINS pDevIns, PSB16DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
+{
+    RT_NOREF(fFlags);
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    /*
+     * Attach driver.
+     */
+    char *pszDesc = NULL;
+    if (RTStrAPrintf(&pszDesc, "Audio driver port (SB16) for LUN #%u", uLUN) <= 0)
+        AssertReleaseMsgReturn(pszDesc,
+                               ("Not enough memory for SB16 driver port description of LUN #%u\n", uLUN),
+                               VERR_NO_MEMORY);
+
+    PPDMIBASE pDrvBase;
+    int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
+                                   &pThis->IBase, &pDrvBase, pszDesc);
+    if (RT_SUCCESS(rc))
+    {
+        if (pDrv == NULL)
+            pDrv = (PSB16DRIVER)RTMemAllocZ(sizeof(SB16DRIVER));
+        if (pDrv)
+        {
+            pDrv->pDrvBase   = pDrvBase;
+            pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
+            AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
+            pDrv->pSB16State = pThis;
+            pDrv->uLUN       = uLUN;
+
+            /*
+             * For now we always set the driver at LUN 0 as our primary
+             * host backend. This might change in the future.
+             */
+            if (pDrv->uLUN == 0)
+                pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
+
+            LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
+
+            /* Attach to driver list if not attached yet. */
+            if (!pDrv->fAttached)
+            {
+                RTListAppend(&pThis->lstDrv, &pDrv->Node);
+                pDrv->fAttached = true;
+            }
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
+    {
+        LogFunc(("No attached driver for LUN #%u\n", uLUN));
+    }
+    else if (RT_FAILURE(rc))
+        AssertMsgFailed(("Failed to attach SB16 LUN #%u (\"%s\"), rc=%Rrc\n",
+                        uLUN, pszDesc, rc));
+
+    if (RT_FAILURE(rc))
+    {
+        /* Only free this string on failure;
+         * must remain valid for the live of the driver instance. */
+        RTStrFree(pszDesc);
+    }
+
+    LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
+    return rc;
+}
+
+/**
+ * Attach command.
+ *
+ * This is called to let the device attach to a driver for a specified LUN
+ * during runtime. This is not called during VM construction, the device
+ * constructor has to attach to all the available drivers.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns     The device instance.
+ * @param   uLUN        The logical unit which is being detached.
+ * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
+ */
+static DECLCALLBACK(int) sb16Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
+{
+    return sb16AttachInternal(pDevIns, NULL /* pDrv */, uLUN, fFlags);
+}
+
+static DECLCALLBACK(void) sb16Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
+{
+    RT_NOREF(pDevIns, uLUN, fFlags);
+    LogFunc(("iLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
+}
+
+/**
+ * Re-attach.
+ *
+ * @returns VBox status code.
+ * @param   pThis       Device instance.
+ * @param   pDrv        Driver instance used for attaching to.
+ *                      If NULL is specified, a new driver will be created and appended
+ *                      to the driver list.
+ * @param   uLUN        The logical unit which is being re-detached.
+ * @param   pszDriver   Driver name.
+ */
+static int sb16Reattach(PSB16STATE pThis, PSB16DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
+{
+    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
+
+    PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
+    PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
+    PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/sb16/0/");
+
+    /* Remove LUN branch. */
+    CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
+
+    if (pDrv)
+    {
+        /* Re-use the driver instance so detach it before. */
+        int rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
+
+    int rc = VINF_SUCCESS;
+    do
+    {
+        PCFGMNODE pLunL0;
+        rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN);        RC_CHECK();
+        rc = CFGMR3InsertString(pLunL0, "Driver",       "AUDIO");       RC_CHECK();
+        rc = CFGMR3InsertNode(pLunL0,   "Config/",       NULL);         RC_CHECK();
+
+        PCFGMNODE pLunL1, pLunL2;
+        rc = CFGMR3InsertNode  (pLunL0, "AttachedDriver/", &pLunL1);    RC_CHECK();
+        rc = CFGMR3InsertNode  (pLunL1,  "Config/",        &pLunL2);    RC_CHECK();
+        rc = CFGMR3InsertString(pLunL1,  "Driver",          pszDriver); RC_CHECK();
+
+        rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver);      RC_CHECK();
+
+    } while (0);
+
+    if (RT_SUCCESS(rc))
+        rc = sb16AttachInternal(pThis->pDevInsR3, pDrv, uLUN, 0 /* fFlags */);
+
+    LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
+
+#undef RC_CHECK
+
+    return rc;
+}
+
+static int magic_of_irq(int irq)
+{
+    switch (irq)
+    {
+        case 5:
+            return 2;
+        case 7:
+            return 4;
+        case 9:
+            return 1;
+        case 10:
+            return 8;
+        default:
+            break;
+    }
+
+    LogFlowFunc(("bad irq %d\n", irq));
+    return 2;
+}
+
+static int irq_of_magic(int magic)
+{
+    switch (magic)
+    {
+        case 1:
+            return 9;
+        case 2:
+            return 5;
+        case 4:
+            return 7;
+        case 8:
+            return 10;
+        default:
+            break;
+    }
+
+    LogFlowFunc(("bad irq magic %d\n", magic));
+    return -1;
+}
+
+#if 0 // unused
+static inline void log_dsp(PSB16STATE pThis)
+{
+    LogFlowFunc(("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
+                 pThis->fmt_stereo ? "Stereo" : "Mono",
+                 pThis->fmt_signed ? "Signed" : "Unsigned",
+                 pThis->fmt_bits,
+                 pThis->dma_auto ? "Auto" : "Single",
+                 pThis->block_size,
+                 pThis->freq,
+                 pThis->time_const,
+                 pThis->speaker));
+}
+#endif
+
+static void sb16SpeakerControl(PSB16STATE pThis, int on)
+{
+    pThis->speaker = on;
+    /* AUD_enable (pThis->voice, on); */
+}
+
+static void sb16Control(PSB16STATE pThis, int hold)
+{
+    int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
+    pThis->dma_running = hold;
+
+    LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
+
+    PSB16DRIVER pDrv;
+    if (hold)
+    {
+        PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 1);
+        PDMDevHlpDMASchedule (pThis->pDevInsR3);
+        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+            pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+                                           pDrv->Out.pStrmOut, true /* fEnable */);
+    }
+    else
+    {
+        PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 0);
+        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+            pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+                                           pDrv->Out.pStrmOut, false /* fEnable */);
+    }
+}
+
+static DECLCALLBACK(void) sb16TimerIRQ(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
+{
+    RT_NOREF(pDevIns, pTimer);
+    PSB16STATE pThis = (PSB16STATE)pvThis;
+    pThis->can_write = 1;
+    PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
+}
+
+#define DMA8_AUTO 1
+#define DMA8_HIGH 2
+
+static void continue_dma8(PSB16STATE pThis)
+{
+    if (pThis->freq > 0)
+    {
+        PDMAUDIOSTREAMCFG streamCfg;
+        streamCfg.uHz           = pThis->freq;
+        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
+        streamCfg.enmFormat     = pThis->fmt;
+        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+        int rc = sb16OpenOut(pThis, &streamCfg);
+        AssertRC(rc);
+    }
+
+    sb16Control(pThis, 1);
+}
+
+static void dma_cmd8(PSB16STATE pThis, int mask, int dma_len)
+{
+    pThis->fmt        = AUD_FMT_U8;
+    pThis->use_hdma   = 0;
+    pThis->fmt_bits   = 8;
+    pThis->fmt_signed = 0;
+    pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
+
+    if (-1 == pThis->time_const)
+    {
+        if (pThis->freq <= 0)
+            pThis->freq = 11025;
+    }
+    else
+    {
+        int tmp = (256 - pThis->time_const);
+        pThis->freq = (1000000 + (tmp / 2)) / tmp;
+    }
+
+    if (dma_len != -1)
+    {
+        pThis->block_size = dma_len << pThis->fmt_stereo;
+    }
+    else
+    {
+        /* This is apparently the only way to make both Act1/PL
+           and SecondReality/FC work
+
+           r=andy Wow, actually someone who remembers Future Crew :-)
+
+           Act1 sets block size via command 0x48 and it's an odd number
+           SR does the same with even number
+           Both use stereo, and Creatives own documentation states that
+           0x48 sets block size in bytes less one.. go figure */
+        pThis->block_size &= ~pThis->fmt_stereo;
+    }
+
+    pThis->freq >>= pThis->fmt_stereo;
+    pThis->left_till_irq = pThis->block_size;
+    pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo);
+    /* pThis->highspeed = (mask & DMA8_HIGH) != 0; */
+    pThis->dma_auto = (mask & DMA8_AUTO) != 0;
+    pThis->align = (1 << pThis->fmt_stereo) - 1;
+
+    if (pThis->block_size & pThis->align)
+        LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
+                     pThis->block_size, pThis->align + 1));
+
+    LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
+                 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
+                 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
+
+    continue_dma8(pThis);
+    sb16SpeakerControl(pThis, 1);
+}
+
+static void dma_cmd(PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
+{
+    pThis->use_hdma   = cmd < 0xc0;
+    pThis->fifo       = (cmd >> 1) & 1;
+    pThis->dma_auto   = (cmd >> 2) & 1;
+    pThis->fmt_signed = (d0 >> 4) & 1;
+    pThis->fmt_stereo = (d0 >> 5) & 1;
+
+    switch (cmd >> 4)
+    {
+        case 11:
+            pThis->fmt_bits = 16;
+            break;
+
+        case 12:
+            pThis->fmt_bits = 8;
+            break;
+    }
+
+    if (-1 != pThis->time_const)
+    {
+#if 1
+        int tmp = 256 - pThis->time_const;
+        pThis->freq = (1000000 + (tmp / 2)) / tmp;
+#else
+        /* pThis->freq = 1000000 / ((255 - pThis->time_const) << pThis->fmt_stereo); */
+        pThis->freq = 1000000 / ((255 - pThis->time_const));
+#endif
+        pThis->time_const = -1;
+    }
+
+    pThis->block_size = dma_len + 1;
+    pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
+    if (!pThis->dma_auto)
+    {
+        /*
+         * It is clear that for DOOM and auto-init this value
+         * shouldn't take stereo into account, while Miles Sound Systems
+         * setsound.exe with single transfer mode wouldn't work without it
+         * wonders of SB16 yet again.
+         */
+        pThis->block_size <<= pThis->fmt_stereo;
+    }
+
+    LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
+                 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
+                 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
+
+    if (16 == pThis->fmt_bits)
+        pThis->fmt = pThis->fmt_signed ? AUD_FMT_S16 : AUD_FMT_U16;
+    else
+        pThis->fmt = pThis->fmt_signed ? AUD_FMT_S8 : AUD_FMT_U8;
+
+    pThis->left_till_irq = pThis->block_size;
+
+    pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo) << ((pThis->fmt_bits == 16) ? 1 : 0);
+    pThis->highspeed = 0;
+    pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
+    if (pThis->block_size & pThis->align)
+    {
+        LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
+                     pThis->block_size, pThis->align + 1));
+    }
+
+    if (pThis->freq)
+    {
+        PDMAUDIOSTREAMCFG streamCfg;
+        streamCfg.uHz           = pThis->freq;
+        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
+        streamCfg.enmFormat     = pThis->fmt;
+        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+        int rc = sb16OpenOut(pThis, &streamCfg);
+        AssertRC(rc);
+    }
+
+    sb16Control(pThis, 1);
+    sb16SpeakerControl(pThis, 1);
+}
+
+static inline void dsp_out_data (PSB16STATE pThis, uint8_t val)
+{
+    LogFlowFunc(("outdata %#x\n", val));
+    if ((size_t) pThis->out_data_len < sizeof (pThis->out_data)) {
+        pThis->out_data[pThis->out_data_len++] = val;
+    }
+}
+
+static inline uint8_t dsp_get_data (PSB16STATE pThis)
+{
+    if (pThis->in_index) {
+        return pThis->in2_data[--pThis->in_index];
+    }
+    else {
+        LogFlowFunc(("buffer underflow\n"));
+        return 0;
+    }
+}
+
+static void sb16HandleCommand(PSB16STATE pThis, uint8_t cmd)
+{
+    LogFlowFunc(("command %#x\n", cmd));
+
+    if (cmd > 0xaf && cmd < 0xd0)
+    {
+        if (cmd & 8) /** @todo Handle recording. */
+            LogFlowFunc(("ADC not yet supported (command %#x)\n", cmd));
+
+        switch (cmd >> 4)
+        {
+            case 11:
+            case 12:
+                break;
+            default:
+                LogFlowFunc(("%#x wrong bits\n", cmd));
+        }
+
+        pThis->needed_bytes = 3;
+    }
+    else
+    {
+        pThis->needed_bytes = 0;
+
+        switch (cmd)
+        {
+            case 0x03:
+                dsp_out_data(pThis, 0x10); /* pThis->csp_param); */
+                goto warn;
+
+            case 0x04:
+                pThis->needed_bytes = 1;
+                goto warn;
+
+            case 0x05:
+                pThis->needed_bytes = 2;
+                goto warn;
+
+            case 0x08:
+                /* __asm__ ("int3"); */
+                goto warn;
+
+            case 0x0e:
+                pThis->needed_bytes = 2;
+                goto warn;
+
+            case 0x09:
+                dsp_out_data(pThis, 0xf8);
+                goto warn;
+
+            case 0x0f:
+                pThis->needed_bytes = 1;
+                goto warn;
+
+            case 0x10:
+                pThis->needed_bytes = 1;
+                goto warn;
+
+            case 0x14:
+                pThis->needed_bytes = 2;
+                pThis->block_size = 0;
+                break;
+
+            case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
+                dma_cmd8(pThis, DMA8_AUTO, -1);
+                break;
+
+            case 0x20:              /* Direct ADC, Juice/PL */
+                dsp_out_data(pThis, 0xff);
+                goto warn;
+
+            case 0x35:
+                LogFlowFunc(("0x35 - MIDI command not implemented\n"));
+                break;
+
+            case 0x40:
+                pThis->freq = -1;
+                pThis->time_const = -1;
+                pThis->needed_bytes = 1;
+                break;
+
+            case 0x41:
+                pThis->freq = -1;
+                pThis->time_const = -1;
+                pThis->needed_bytes = 2;
+                break;
+
+            case 0x42:
+                pThis->freq = -1;
+                pThis->time_const = -1;
+                pThis->needed_bytes = 2;
+                goto warn;
+
+            case 0x45:
+                dsp_out_data(pThis, 0xaa);
+                goto warn;
+
+            case 0x47:                /* Continue Auto-Initialize DMA 16bit */
+                break;
+
+            case 0x48:
+                pThis->needed_bytes = 2;
+                break;
+
+            case 0x74:
+                pThis->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
+                LogFlowFunc(("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"));
+                break;
+
+            case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
+                pThis->needed_bytes = 2;
+                LogFlowFunc(("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"));
+                break;
+
+            case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
+                pThis->needed_bytes = 2;
+                LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"));
+                break;
+
+            case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
+                pThis->needed_bytes = 2;
+                LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"));
+                break;
+
+            case 0x7d:
+                LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"));
+                LogFlowFunc(("not implemented\n"));
+                break;
+
+            case 0x7f:
+                LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"));
+                LogFlowFunc(("not implemented\n"));
+                break;
+
+            case 0x80:
+                pThis->needed_bytes = 2;
+                break;
+
+            case 0x90:
+            case 0x91:
+                dma_cmd8(pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
+                break;
+
+            case 0xd0:              /* halt DMA operation. 8bit */
+                sb16Control(pThis, 0);
+                break;
+
+            case 0xd1:              /* speaker on */
+                sb16SpeakerControl(pThis, 1);
+                break;
+
+            case 0xd3:              /* speaker off */
+                sb16SpeakerControl(pThis, 0);
+                break;
+
+            case 0xd4:              /* continue DMA operation. 8bit */
+                /* KQ6 (or maybe Sierras audblst.drv in general) resets
+                   the frequency between halt/continue */
+                continue_dma8(pThis);
+                break;
+
+            case 0xd5:              /* halt DMA operation. 16bit */
+                sb16Control(pThis, 0);
+                break;
+
+            case 0xd6:              /* continue DMA operation. 16bit */
+                sb16Control(pThis, 1);
+                break;
+
+            case 0xd9:              /* exit auto-init DMA after this block. 16bit */
+                pThis->dma_auto = 0;
+                break;
+
+            case 0xda:              /* exit auto-init DMA after this block. 8bit */
+                pThis->dma_auto = 0;
+                break;
+
+            case 0xe0:              /* DSP identification */
+                pThis->needed_bytes = 1;
+                break;
+
+            case 0xe1:
+                dsp_out_data(pThis, pThis->ver & 0xff);
+                dsp_out_data(pThis, pThis->ver >> 8);
+                break;
+
+            case 0xe2:
+                pThis->needed_bytes = 1;
+                goto warn;
+
+            case 0xe3:
+            {
+                for (int i = sizeof (e3) - 1; i >= 0; --i)
+                    dsp_out_data(pThis, e3[i]);
+
+                break;
+            }
+
+            case 0xe4:              /* write test reg */
+                pThis->needed_bytes = 1;
+                break;
+
+            case 0xe7:
+                LogFlowFunc(("Attempt to probe for ESS (0xe7)?\n"));
+                break;
+
+            case 0xe8:              /* read test reg */
+                dsp_out_data(pThis, pThis->test_reg);
+                break;
+
+            case 0xf2:
+            case 0xf3:
+                dsp_out_data(pThis, 0xaa);
+                pThis->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
+                PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
+                break;
+
+            case 0xf8:
+                /* Undocumented, used by old Creative diagnostic programs. */
+                dsp_out_data (pThis, 0);
+                goto warn;
+
+            case 0xf9:
+                pThis->needed_bytes = 1;
+                goto warn;
+
+            case 0xfa:
+                dsp_out_data (pThis, 0);
+                goto warn;
+
+            case 0xfc:              /* FIXME */
+                dsp_out_data (pThis, 0);
+                goto warn;
+
+            default:
+                LogFlowFunc(("Unrecognized command %#x\n", cmd));
+                break;
+        }
+    }
+
+    if (!pThis->needed_bytes)
+        LogFlow(("\n"));
+
+exit:
+
+     if (!pThis->needed_bytes)
+        pThis->cmd = -1;
+     else
+        pThis->cmd = cmd;
+
+    return;
+
+warn:
+    LogFlowFunc(("warning: command %#x,%d is not truly understood yet\n",
+                 cmd, pThis->needed_bytes));
+    goto exit;
+}
+
+static uint16_t dsp_get_lohi (PSB16STATE pThis)
+{
+    uint8_t hi = dsp_get_data (pThis);
+    uint8_t lo = dsp_get_data (pThis);
+    return (hi << 8) | lo;
+}
+
+static uint16_t dsp_get_hilo (PSB16STATE pThis)
+{
+    uint8_t lo = dsp_get_data (pThis);
+    uint8_t hi = dsp_get_data (pThis);
+    return (hi << 8) | lo;
+}
+
+static void complete(PSB16STATE pThis)
+{
+    int d0, d1, d2;
+    LogFlowFunc(("complete command %#x, in_index %d, needed_bytes %d\n",
+            pThis->cmd, pThis->in_index, pThis->needed_bytes));
+
+    if (pThis->cmd > 0xaf && pThis->cmd < 0xd0)
+    {
+        d2 = dsp_get_data (pThis);
+        d1 = dsp_get_data (pThis);
+        d0 = dsp_get_data (pThis);
+
+        if (pThis->cmd & 8)
+            LogFlowFunc(("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
+        else
+        {
+            LogFlowFunc(("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
+            dma_cmd(pThis, pThis->cmd, d0, d1 + (d2 << 8));
+        }
+    }
+    else
+    {
+        switch (pThis->cmd)
+        {
+        case 0x04:
+            pThis->csp_mode = dsp_get_data (pThis);
+            pThis->csp_reg83r = 0;
+            pThis->csp_reg83w = 0;
+            LogFlowFunc(("CSP command 0x04: mode=%#x\n", pThis->csp_mode));
+            break;
+
+        case 0x05:
+            pThis->csp_param = dsp_get_data (pThis);
+            pThis->csp_value = dsp_get_data (pThis);
+            LogFlowFunc(("CSP command 0x05: param=%#x value=%#x\n",
+                    pThis->csp_param,
+                    pThis->csp_value));
+            break;
+
+        case 0x0e:
+        {
+            d0 = dsp_get_data(pThis);
+            d1 = dsp_get_data(pThis);
+            LogFlowFunc(("write CSP register %d <- %#x\n", d1, d0));
+            if (d1 == 0x83)
+            {
+                LogFlowFunc(("0x83[%d] <- %#x\n", pThis->csp_reg83r, d0));
+                pThis->csp_reg83[pThis->csp_reg83r % 4] = d0;
+                pThis->csp_reg83r += 1;
+            }
+            else
+                pThis->csp_regs[d1] = d0;
+            break;
+        }
+
+        case 0x0f:
+            d0 = dsp_get_data(pThis);
+            LogFlowFunc(("read CSP register %#x -> %#x, mode=%#x\n", d0, pThis->csp_regs[d0], pThis->csp_mode));
+            if (d0 == 0x83)
+            {
+                LogFlowFunc(("0x83[%d] -> %#x\n",
+                        pThis->csp_reg83w,
+                        pThis->csp_reg83[pThis->csp_reg83w % 4]));
+                dsp_out_data (pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
+                pThis->csp_reg83w += 1;
+            }
+            else
+                dsp_out_data(pThis, pThis->csp_regs[d0]);
+            break;
+
+        case 0x10:
+            d0 = dsp_get_data(pThis);
+            LogFlowFunc(("cmd 0x10 d0=%#x\n", d0));
+            break;
+
+        case 0x14:
+            dma_cmd8(pThis, 0, dsp_get_lohi (pThis) + 1);
+            break;
+
+        case 0x40:
+            pThis->time_const = dsp_get_data(pThis);
+            LogFlowFunc(("set time const %d\n", pThis->time_const));
+            break;
+
+        case 0x42:              /* FT2 sets output freq with this, go figure */
+#if 0
+            LogFlowFunc(("cmd 0x42 might not do what it think it should\n"));
+#endif
+        case 0x41:
+            pThis->freq = dsp_get_hilo(pThis);
+            LogFlowFunc(("set freq %d\n", pThis->freq));
+            break;
+
+        case 0x48:
+            pThis->block_size = dsp_get_lohi(pThis) + 1;
+            LogFlowFunc(("set dma block len %d\n", pThis->block_size));
+            break;
+
+        case 0x74:
+        case 0x75:
+        case 0x76:
+        case 0x77:
+            /* ADPCM stuff, ignore */
+            break;
+
+        case 0x80:
+        {
+            int freq, samples, bytes;
+            uint64_t ticks;
+
+            freq = pThis->freq > 0 ? pThis->freq : 11025;
+            samples = dsp_get_lohi (pThis) + 1;
+            bytes = samples << pThis->fmt_stereo << ((pThis->fmt_bits == 16) ? 1 : 0);
+            ticks = (bytes * TMTimerGetFreq(pThis->pTimerIRQ)) / freq;
+            if (ticks < TMTimerGetFreq(pThis->pTimerIRQ) / 1024)
+                PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
+            else
+                TMTimerSet(pThis->pTimerIRQ, TMTimerGet(pThis->pTimerIRQ) + ticks);
+            LogFlowFunc(("mix silence: %d samples, %d bytes, %RU64 ticks\n", samples, bytes, ticks));
+            break;
+        }
+
+        case 0xe0:
+            d0 = dsp_get_data(pThis);
+            pThis->out_data_len = 0;
+            LogFlowFunc(("E0 data = %#x\n", d0));
+            dsp_out_data(pThis, ~d0);
+            break;
+
+        case 0xe2:
+            d0 = dsp_get_data(pThis);
+            LogFlow(("SB16:E2 = %#x\n", d0));
+            break;
+
+        case 0xe4:
+            pThis->test_reg = dsp_get_data(pThis);
+            break;
+
+        case 0xf9:
+            d0 = dsp_get_data(pThis);
+            LogFlowFunc(("command 0xf9 with %#x\n", d0));
+            switch (d0) {
+            case 0x0e:
+                dsp_out_data(pThis, 0xff);
+                break;
+
+            case 0x0f:
+                dsp_out_data(pThis, 0x07);
+                break;
+
+            case 0x37:
+                dsp_out_data(pThis, 0x38);
+                break;
+
+            default:
+                dsp_out_data(pThis, 0x00);
+                break;
+            }
+            break;
+
+        default:
+            LogFlowFunc(("complete: unrecognized command %#x\n", pThis->cmd));
+            return;
+        }
+    }
+
+    LogFlow(("\n"));
+    pThis->cmd = -1;
+    return;
+}
+
+static uint8_t sb16MixRegToVol(PSB16STATE pThis, int reg)
+{
+    /* The SB16 mixer has a 0 to -62dB range in 32 levels (2dB each step).
+     * We use a 0 to -96dB range in 256 levels (0.375dB each step).
+     * Only the top 5 bits of a mixer register are used.
+     */
+    uint8_t steps = 31 - (pThis->mixer_regs[reg] >> 3);
+    uint8_t vol   = 255 - steps * 16 / 3;   /* (2dB*8) / (0.375dB*8) */
+    return vol;
+}
+
+static void sb16SetMasterVolume(PSB16STATE pThis)
+{
+    /* There's no mute switch, only volume controls. */
+    uint8_t lvol = sb16MixRegToVol(pThis, 0x30);
+    uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
+    PDMAUDIOVOLUME vol = { false, lvol, rvol };
+    AudioMixerSetMasterVolume(pThis->pMixer, &vol);
+}
+
+static void sb16SetPcmOutVolume(PSB16STATE pThis)
+{
+    /* There's no mute switch, only volume controls. */
+    uint8_t lvol = sb16MixRegToVol(pThis, 0x32);
+    uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
+    PDMAUDIOVOLUME vol = { false, lvol, rvol };
+    AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
+}
+
+static void sb16ResetLegacy(PSB16STATE pThis)
+{
+    pThis->freq       = 11025;
+    pThis->fmt_signed = 0;
+    pThis->fmt_bits   = 8;
+    pThis->fmt_stereo = 0;
+
+    PDMAUDIOSTREAMCFG streamCfg;
+    streamCfg.uHz           = pThis->freq;
+    streamCfg.cChannels     = 1; /* Mono */
+    streamCfg.enmFormat     = AUD_FMT_U8;
+    streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+    int rc2 = sb16OpenOut(pThis, &streamCfg);
+    AssertRC(rc2);
+}
+
+static void sb16Reset(PSB16STATE pThis)
+{
+    PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
+    if (pThis->dma_auto)
+    {
+        PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
+        PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
+    }
+
+    pThis->mixer_regs[0x82] = 0;
+    pThis->dma_auto = 0;
+    pThis->in_index = 0;
+    pThis->out_data_len = 0;
+    pThis->left_till_irq = 0;
+    pThis->needed_bytes = 0;
+    pThis->block_size = -1;
+    pThis->nzero = 0;
+    pThis->highspeed = 0;
+    pThis->v2x6 = 0;
+    pThis->cmd = -1;
+
+    dsp_out_data(pThis, 0xaa);
+    sb16SpeakerControl(pThis, 0);
+    sb16Control(pThis, 0);
+    sb16ResetLegacy(pThis);
+}
+
+static IO_WRITE_PROTO(dsp_write)
+{
+    RT_NOREF(cb);
+    PSB16STATE pThis = (PSB16STATE)opaque;
+    int iport = nport - pThis->port;
+
+    LogFlowFunc(("write %#x <- %#x\n", nport, val));
+    switch (iport)
+    {
+        case 0x06:
+            switch (val)
+            {
+                case 0x00:
+                {
+                    if (pThis->v2x6 == 1)
+                    {
+                        if (0 && pThis->highspeed)
+                        {
+                            pThis->highspeed = 0;
+                            PDMDevHlpISASetIrq(pDevIns, pThis->irq, 0);
+                            sb16Control(pThis, 0);
+                        }
+                        else
+                            sb16Reset(pThis);
+                    }
+                    pThis->v2x6 = 0;
+                    break;
+                }
+
+                case 0x01:
+                case 0x03:              /* FreeBSD kludge */
+                    pThis->v2x6 = 1;
+                    break;
+
+                case 0xc6:
+                    pThis->v2x6 = 0;    /* Prince of Persia, csp.sys, diagnose.exe */
+                    break;
+
+                case 0xb8:              /* Panic */
+                    sb16Reset(pThis);
+                    break;
+
+                case 0x39:
+                    dsp_out_data(pThis, 0x38);
+                    sb16Reset(pThis);
+                    pThis->v2x6 = 0x39;
+                    break;
+
+                default:
+                    pThis->v2x6 = val;
+                    break;
+            }
+            break;
+
+        case 0x0c:                      /* Write data or command | write status */
+#if 0
+            if (pThis->highspeed)
+                break;
+#endif
+            if (0 == pThis->needed_bytes)
+            {
+                sb16HandleCommand(pThis, val);
+#if 0
+                if (0 == pThis->needed_bytes) {
+                    log_dsp (pThis);
+                }
+#endif
+            }
+            else
+            {
+                if (pThis->in_index == sizeof (pThis->in2_data))
+                {
+                    LogFlowFunc(("in data overrun\n"));
+                }
+                else
+                {
+                    pThis->in2_data[pThis->in_index++] = val;
+                    if (pThis->in_index == pThis->needed_bytes)
+                    {
+                        pThis->needed_bytes = 0;
+                        complete (pThis);
+#if 0
+                        log_dsp (pThis);
+#endif
+                    }
+                }
+            }
+            break;
+
+        default:
+            LogFlowFunc(("nport=%#x, val=%#x)\n", nport, val));
+            break;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static IO_READ_PROTO(dsp_read)
+{
+    RT_NOREF(pDevIns, cb);
+    PSB16STATE pThis = (PSB16STATE)opaque;
+    int iport, retval, ack = 0;
+
+    iport = nport - pThis->port;
+
+    /** @todo reject non-byte access?
+     *  The spec does not mention a non-byte access so we should check how real hardware behaves. */
+
+    switch (iport)
+    {
+        case 0x06:                  /* reset */
+            retval = 0xff;
+            break;
+
+        case 0x0a:                  /* read data */
+            if (pThis->out_data_len)
+            {
+                retval = pThis->out_data[--pThis->out_data_len];
+                pThis->last_read_byte = retval;
+            }
+            else
+            {
+                if (pThis->cmd != -1)
+                    LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
+                retval = pThis->last_read_byte;
+                /* goto error; */
+            }
+            break;
+
+        case 0x0c:                  /* 0 can write */
+            retval = pThis->can_write ? 0 : 0x80;
+            break;
+
+        case 0x0d:                  /* timer interrupt clear */
+            /* LogFlowFunc(("timer interrupt clear\n")); */
+            retval = 0;
+            break;
+
+        case 0x0e:                  /* data available status | irq 8 ack */
+            retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
+            if (pThis->mixer_regs[0x82] & 1)
+            {
+                ack = 1;
+                pThis->mixer_regs[0x82] &= ~1;
+                PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
+            }
+            break;
+
+        case 0x0f:                  /* irq 16 ack */
+            retval = 0xff;
+            if (pThis->mixer_regs[0x82] & 2)
+            {
+                ack = 1;
+                pThis->mixer_regs[0x82] &= ~2;
+               PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
+            }
+            break;
+
+        default:
+            goto error;
+    }
+
+    if (!ack)
+        LogFlowFunc(("read %#x -> %#x\n", nport, retval));
+
+    *pu32 = retval;
+    return VINF_SUCCESS;
+
+ error:
+    LogFlowFunc(("warning: dsp_read %#x error\n", nport));
+    return VERR_IOM_IOPORT_UNUSED;
+}
+
+static void sb16MixerReset(PSB16STATE pThis)
+{
+    PSB16DRIVER pDrv;
+
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+        pDrv->Out.phStrmOut = NULL;
+
+    pThis->pSinkOutput = NULL;
+
+    if (pThis->pMixer)
+    {
+        AudioMixerDestroy(pThis->pMixer);
+        pThis->pMixer = NULL;
+    }
+
+    memset(pThis->mixer_regs, 0xff, 0x7f);
+    memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
+
+    pThis->mixer_regs[0x02] = 4;    /* master volume 3bits */
+    pThis->mixer_regs[0x06] = 4;    /* MIDI volume 3bits */
+    pThis->mixer_regs[0x08] = 0;    /* CD volume 3bits */
+    pThis->mixer_regs[0x0a] = 0;    /* voice volume 2bits */
+
+    /* d5=input filt, d3=lowpass filt, d1,d2=input source */
+    pThis->mixer_regs[0x0c] = 0;
+
+    /* d5=output filt, d1=stereo switch */
+    pThis->mixer_regs[0x0e] = 0;
+
+    /* voice volume L d5,d7, R d1,d3 */
+    pThis->mixer_regs[0x04] = (12 << 4) | 12;
+    /* master ... */
+    pThis->mixer_regs[0x22] = (12 << 4) | 12;
+    /* MIDI ... */
+    pThis->mixer_regs[0x26] = (12 << 4) | 12;
+
+    /* master/voice/MIDI L/R volume */
+    for (int i = 0x30; i < 0x36; i++)
+        pThis->mixer_regs[i] = 24 << 3; /* -14 dB */
+
+    /* treble/bass */
+    for (int i = 0x44; i < 0x48; i++)
+        pThis->mixer_regs[i] = 0x80;
+
+    int rc2 = AudioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
+    if (RT_SUCCESS(rc2))
+    {
+        /* Set a default audio format for our mixer. */
+        PDMAUDIOSTREAMCFG streamCfg;
+        streamCfg.uHz           = 44100;
+        streamCfg.cChannels     = 2;
+        streamCfg.enmFormat     = AUD_FMT_S16;
+        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+        rc2 = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
+        AssertRC(rc2);
+
+        /* Add all required audio sinks. */
+        rc2 = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
+                                AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
+        AssertRC(rc2);
+    }
+
+    /* Update the master (mixer) and PCM out volumes. */
+    sb16SetMasterVolume(pThis);
+    sb16SetPcmOutVolume(pThis);
+}
+
+static IO_WRITE_PROTO(mixer_write_indexb)
+{
+    RT_NOREF(pDevIns, cb);
+    PSB16STATE pThis = (PSB16STATE)opaque;
+    (void) nport;
+    pThis->mixer_nreg = val;
+
+    return VINF_SUCCESS;
+}
+
+uint32_t popcount(uint32_t u) /** @todo r=andy WTF? */
+{
+    u = ((u&0x55555555) + ((u>>1)&0x55555555));
+    u = ((u&0x33333333) + ((u>>2)&0x33333333));
+    u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
+    u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
+    u = ( u&0x0000ffff) + (u>>16);
+    return u;
+}
+
+uint32_t lsbindex(uint32_t u)
+{
+    return popcount((u & -(int32_t)u) - 1);
+}
+
+/* Convert SB16 to SB Pro mixer volume (left). */
+static inline void sb16ConvVolumeL(PSB16STATE pThis, unsigned reg, uint8_t val)
+{
+    /* High nibble in SBP mixer. */
+    pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0x0f) | (val & 0xf0);
+}
+
+/* Convert SB16 to SB Pro mixer volume (right). */
+static inline void sb16ConvVolumeR(PSB16STATE pThis, unsigned reg, uint8_t val)
+{
+    /* Low nibble in SBP mixer. */
+    pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0xf0) | (val >> 4);
+}
+
+/* Convert SB Pro to SB16 mixer volume (left + right). */
+static inline void sb16ConvVolumeOldToNew(PSB16STATE pThis, unsigned reg, uint8_t val)
+{
+    /* Left channel. */
+    pThis->mixer_regs[reg + 0] = (val & 0xf0) | RT_BIT(3);
+    /* Right channel (the register immediately following). */
+    pThis->mixer_regs[reg + 1] = (val << 4)   | RT_BIT(3);
+}
+
+static IO_WRITE_PROTO(mixer_write_datab)
+{
+    RT_NOREF(pDevIns, cb);
+    PSB16STATE  pThis = (PSB16STATE)opaque;
+    bool        fUpdateMaster = false;
+    bool        fUpdateStream = false;
+
+    (void) nport;
+    LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
+
+    switch (pThis->mixer_nreg)
+    {
+        case 0x00:
+            sb16MixerReset(pThis);
+            /* And update the actual volume, too. */
+            fUpdateMaster = true;
+            fUpdateStream = true;
+            break;
+
+        case 0x04:  /* Translate from old style voice volume (L/R). */
+            sb16ConvVolumeOldToNew(pThis, 0x32, val);
+            fUpdateStream = true;
+            break;
+
+        case 0x22:  /* Translate from old style master volume (L/R). */
+            sb16ConvVolumeOldToNew(pThis, 0x30, val);
+            fUpdateMaster = true;
+            break;
+
+        case 0x26:  /* Translate from old style MIDI volume (L/R). */
+            sb16ConvVolumeOldToNew(pThis, 0x34, val);
+            break;
+
+        case 0x28:  /* Translate from old style CD volume (L/R). */
+            sb16ConvVolumeOldToNew(pThis, 0x36, val);
+            break;
+
+        case 0x2E:  /* Translate from old style line volume (L/R). */
+            sb16ConvVolumeOldToNew(pThis, 0x38, val);
+            break;
+
+        case 0x30:  /* Translate to old style master volume (L). */
+            sb16ConvVolumeL(pThis, 0x22, val);
+            fUpdateMaster = true;
+            break;
+
+        case 0x31:  /* Translate to old style master volume (R). */
+            sb16ConvVolumeR(pThis, 0x22, val);
+            fUpdateMaster = true;
+            break;
+
+        case 0x32:  /* Translate to old style voice volume (L). */
+            sb16ConvVolumeL(pThis, 0x04, val);
+            fUpdateStream = true;
+            break;
+
+        case 0x33:  /* Translate to old style voice volume (R). */
+            sb16ConvVolumeR(pThis, 0x04, val);
+            fUpdateStream = true;
+            break;
+
+        case 0x34:  /* Translate to old style MIDI volume (L). */
+            sb16ConvVolumeL(pThis, 0x26, val);
+            break;
+
+        case 0x35:  /* Translate to old style MIDI volume (R). */
+            sb16ConvVolumeR(pThis, 0x26, val);
+            break;
+
+        case 0x36:  /* Translate to old style CD volume (L). */
+            sb16ConvVolumeL(pThis, 0x28, val);
+            break;
+
+        case 0x37:  /* Translate to old style CD volume (R). */
+            sb16ConvVolumeR(pThis, 0x28, val);
+            break;
+
+        case 0x38:  /* Translate to old style line volume (L). */
+            sb16ConvVolumeL(pThis, 0x2E, val);
+            break;
+
+        case 0x39:  /* Translate to old style line volume (R). */
+            sb16ConvVolumeR(pThis, 0x2E, val);
+            break;
+
+        case 0x80:
+        {
+            int irq = irq_of_magic(val);
+            LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
+            if (irq > 0)
+                pThis->irq = irq;
+            break;
+        }
+
+        case 0x81:
+        {
+            int dma, hdma;
+
+            dma = lsbindex (val & 0xf);
+            hdma = lsbindex (val & 0xf0);
+            if (dma != pThis->dma || hdma != pThis->hdma)
+                LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
+                         dma, pThis->dma, hdma, pThis->hdma, val));
+#if 0
+            pThis->dma = dma;
+            pThis->hdma = hdma;
+#endif
+            break;
+        }
+
+        case 0x82:
+            LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
+            return VINF_SUCCESS;
+
+        default:
+            if (pThis->mixer_nreg >= 0x80)
+                LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
+            break;
+    }
+
+    pThis->mixer_regs[pThis->mixer_nreg] = val;
+
+    /* Update the master (mixer) volume. */
+    if (fUpdateMaster)
+        sb16SetMasterVolume(pThis);
+
+    /* Update the stream (PCM) volume. */
+    if (fUpdateStream)
+        sb16SetPcmOutVolume(pThis);
+
+    return VINF_SUCCESS;
+}
+
+static IO_WRITE_PROTO(mixer_write)
+{
+    PSB16STATE pThis = (PSB16STATE)opaque;
+    int iport = nport - pThis->port;
+    switch (cb)
+    {
+        case 1:
+            switch (iport)
+            {
+                case 4:
+                    mixer_write_indexb (pDevIns, opaque, nport, val, 1);
+                    break;
+                case 5:
+                    mixer_write_datab (pDevIns, opaque, nport, val, 1);
+                    break;
+            }
+            break;
+        case 2:
+            mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
+            mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
+            break;
+        default:
+            AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
+            break;
+    }
+    return VINF_SUCCESS;
+}
+
+static IO_READ_PROTO(mixer_read)
+{
+    RT_NOREF(pDevIns, cb);
+    PSB16STATE pThis = (PSB16STATE)opaque;
+
+    (void) nport;
+#ifndef DEBUG_SB16_MOST
+    if (pThis->mixer_nreg != 0x82) {
+        LogFlowFunc(("mixer_read[%#x] -> %#x\n",
+                pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
+    }
+#else
+    LogFlowFunc(("mixer_read[%#x] -> %#x\n",
+            pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
+#endif
+    *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
+    return VINF_SUCCESS;
+}
+
+static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
+                          uint32_t dma_len, int len)
+{
+    uint8_t  tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
+    uint32_t cbToWrite = len;
+    uint32_t cbWrittenTotal = 0;
+
+    while (cbToWrite)
+    {
+        uint32_t cbToRead;
+        uint32_t cbRead;
+
+        cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
+        if (cbToRead > sizeof(tmpbuf))
+            cbToRead = sizeof(tmpbuf);
+
+        int rc = PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
+        AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
+
+        uint32_t cbWritten;
+
+        /* Just multiplex the output to the connected backends.
+         * No need to utilize the virtual mixer here (yet). */
+        PSB16DRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+        {
+            int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+                                                 tmpbuf, cbToRead, &cbWritten);
+            LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32\n", pDrv->uLUN, rc2, cbWritten)); NOREF(rc2);
+        }
+
+        Assert(cbToWrite >= cbToRead);
+        cbToWrite      -= cbToRead;
+        dma_pos         = (dma_pos + cbToRead) % dma_len;
+        cbWrittenTotal += cbToRead;
+
+        if (!cbRead)
+            break;
+    }
+
+    return cbWrittenTotal;
+}
+
+static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
+{
+    RT_NOREF(pDevIns);
+    PSB16STATE pThis = (PSB16STATE)opaque;
+    int till, copy, written, free;
+
+    if (pThis->block_size <= 0)
+    {
+        LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
+                     pThis->block_size, nchan, dma_pos, dma_len));
+        return dma_pos;
+    }
+
+    if (pThis->left_till_irq < 0)
+        pThis->left_till_irq = pThis->block_size;
+
+    PSB16DRIVER pDrv;
+
+    uint32_t cbOutMin = UINT32_MAX;
+    uint32_t cbOut;
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
+                                                   NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
+        if (RT_SUCCESS(rc2))
+            cbOutMin = RT_MIN(cbOutMin, cbOut);
+    }
+
+    LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
+    if (cbOutMin == UINT32_MAX)
+    {
+        free = dma_len;
+    }
+    else
+    {
+        free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
+        if ((free <= 0) || !dma_len)
+            return dma_pos;
+    }
+
+    copy = free;
+    till = pThis->left_till_irq;
+
+#ifdef DEBUG_SB16_MOST
+    LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
+#endif
+
+    if (copy >= till)
+    {
+        if (0 == pThis->dma_auto)
+        {
+            copy = till;
+        }
+        else
+        {
+            if (copy >= till + pThis->block_size)
+                copy = till; /* Make sure we won't skip IRQs. */
+        }
+    }
+
+    written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
+    dma_pos = (dma_pos + written) % dma_len;
+    pThis->left_till_irq -= written;
+
+    if (pThis->left_till_irq <= 0)
+    {
+        pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
+        PDMDevHlpISASetIrq(pDevIns, pThis->irq, 1);
+        if (0 == pThis->dma_auto)
+        {
+            sb16Control(pThis, 0);
+            sb16SpeakerControl(pThis, 0);
+        }
+    }
+
+#ifdef DEBUG_SB16_MOST
+    LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
+                 dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
+                 pThis->block_size));
+#endif
+
+    while (pThis->left_till_irq <= 0)
+        pThis->left_till_irq += pThis->block_size;
+
+    return dma_pos;
+}
+
+static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
+{
+    RT_NOREF(pDevIns);
+    PSB16STATE pThis = (PSB16STATE)pvUser;
+    Assert(pThis == PDMINS_2_DATA(pDevIns, PSB16STATE));
+    AssertPtr(pThis);
+
+    uint32_t cbInMax  = 0;
+    uint32_t cbOutMin = UINT32_MAX;
+
+    PSB16DRIVER pDrv;
+
+    uint64_t cTicksNow     = TMTimerGet(pTimer);
+    uint64_t cTicksElapsed = cTicksNow  - pThis->uTimerTSIO;
+    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
+
+    pThis->uTimerTSIO = cTicksNow;
+
+    /*
+     * Calculate the mixer's (fixed) sampling rate.
+     */
+    AssertPtr(pThis->pMixer);
+
+    PDMAUDIOSTREAMCFG mixerStrmCfg;
+    int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
+    AssertRC(rc);
+
+    PDMPCMPROPS mixerStrmProps;
+    rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
+    AssertRC(rc);
+
+    uint32_t cMixerSamplesMin  = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
+    uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
+
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        uint32_t cbIn = 0;
+        uint32_t cbOut = 0;
+
+        rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
+                                              &cbIn, &cbOut, NULL /* cSamplesLive */);
+        if (RT_SUCCESS(rc))
+            rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
+
+#ifdef DEBUG_TIMER
+        LogFlowFunc(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
+#endif
+        /* If we there was an error handling (available) output or there simply is no output available,
+         * then calculate the minimum data rate which must be processed by the device emulation in order
+         * to function correctly.
+         *
+         * This is not the optimal solution, but as we have to deal with this on a timer-based approach
+         * (until we have the audio callbacks) we need to have device' DMA engines running. */
+        if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+        {
+            /* Use the mixer's (fixed) sampling rate. */
+            cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
+            continue;
+        }
+
+        const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+        if (   RT_FAILURE(rc)
+            || !fIsActiveOut)
+        {
+            uint32_t cSamplesMin  = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+            uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
+
+            Log2Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
+
+            cbOut = RT_MAX(cbOut, cbSamplesMin);
+        }
+
+        cbOutMin = RT_MIN(cbOutMin, cbOut);
+        cbInMax  = RT_MAX(cbInMax, cbIn);
+    }
+
+    Log2Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
+
+    if (cbOutMin == UINT32_MAX)
+        cbOutMin = 0;
+
+    /*
+     * Playback.
+     */
+    if (cbOutMin)
+    {
+        Assert(cbOutMin != UINT32_MAX);
+
+        /* New space available, see if we can transfer more. */
+        PDMDevHlpDMASchedule(pThis->pDevInsR3);
+    }
+
+    /*
+     * Recording.
+     */
+    /** @todo Implement recording. */
+
+    /* Kick the timer again. */
+    uint64_t cTicks = pThis->cTimerTicksIO;
+    /** @todo adjust cTicks down by now much cbOutMin represents. */
+    TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
+}
+
+static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
+{
+    SSMR3PutS32(pSSM, pThis->irq);
+    SSMR3PutS32(pSSM, pThis->dma);
+    SSMR3PutS32(pSSM, pThis->hdma);
+    SSMR3PutS32(pSSM, pThis->port);
+    SSMR3PutS32(pSSM, pThis->ver);
+    SSMR3PutS32(pSSM, pThis->in_index);
+    SSMR3PutS32(pSSM, pThis->out_data_len);
+    SSMR3PutS32(pSSM, pThis->fmt_stereo);
+    SSMR3PutS32(pSSM, pThis->fmt_signed);
+    SSMR3PutS32(pSSM, pThis->fmt_bits);
+
+    SSMR3PutU32(pSSM, pThis->fmt);
+
+    SSMR3PutS32(pSSM, pThis->dma_auto);
+    SSMR3PutS32(pSSM, pThis->block_size);
+    SSMR3PutS32(pSSM, pThis->fifo);
+    SSMR3PutS32(pSSM, pThis->freq);
+    SSMR3PutS32(pSSM, pThis->time_const);
+    SSMR3PutS32(pSSM, pThis->speaker);
+    SSMR3PutS32(pSSM, pThis->needed_bytes);
+    SSMR3PutS32(pSSM, pThis->cmd);
+    SSMR3PutS32(pSSM, pThis->use_hdma);
+    SSMR3PutS32(pSSM, pThis->highspeed);
+    SSMR3PutS32(pSSM, pThis->can_write);
+    SSMR3PutS32(pSSM, pThis->v2x6);
+
+    SSMR3PutU8 (pSSM, pThis->csp_param);
+    SSMR3PutU8 (pSSM, pThis->csp_value);
+    SSMR3PutU8 (pSSM, pThis->csp_mode);
+    SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
+    SSMR3PutMem(pSSM, pThis->csp_regs, 256);
+    SSMR3PutU8 (pSSM, pThis->csp_index);
+    SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
+    SSMR3PutS32(pSSM, pThis->csp_reg83r);
+    SSMR3PutS32(pSSM, pThis->csp_reg83w);
+
+    SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
+    SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
+    SSMR3PutU8 (pSSM, pThis->test_reg);
+    SSMR3PutU8 (pSSM, pThis->last_read_byte);
+
+    SSMR3PutS32(pSSM, pThis->nzero);
+    SSMR3PutS32(pSSM, pThis->left_till_irq);
+    SSMR3PutS32(pSSM, pThis->dma_running);
+    SSMR3PutS32(pSSM, pThis->bytes_per_second);
+    SSMR3PutS32(pSSM, pThis->align);
+
+    SSMR3PutS32(pSSM, pThis->mixer_nreg);
+    SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
+
+}
+
+static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis, int version_id)
+{
+    RT_NOREF(version_id);
+    SSMR3GetS32(pSSM, &pThis->irq);
+    SSMR3GetS32(pSSM, &pThis->dma);
+    SSMR3GetS32(pSSM, &pThis->hdma);
+    SSMR3GetS32(pSSM, &pThis->port);
+    SSMR3GetS32(pSSM, &pThis->ver);
+    SSMR3GetS32(pSSM, &pThis->in_index);
+    SSMR3GetS32(pSSM, &pThis->out_data_len);
+    SSMR3GetS32(pSSM, &pThis->fmt_stereo);
+    SSMR3GetS32(pSSM, &pThis->fmt_signed);
+    SSMR3GetS32(pSSM, &pThis->fmt_bits);
+
+    SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
+
+    SSMR3GetS32(pSSM, &pThis->dma_auto);
+    SSMR3GetS32(pSSM, &pThis->block_size);
+    SSMR3GetS32(pSSM, &pThis->fifo);
+    SSMR3GetS32(pSSM, &pThis->freq);
+    SSMR3GetS32(pSSM, &pThis->time_const);
+    SSMR3GetS32(pSSM, &pThis->speaker);
+    SSMR3GetS32(pSSM, &pThis->needed_bytes);
+    SSMR3GetS32(pSSM, &pThis->cmd);
+    SSMR3GetS32(pSSM, &pThis->use_hdma);
+    SSMR3GetS32(pSSM, &pThis->highspeed);
+    SSMR3GetS32(pSSM, &pThis->can_write);
+    SSMR3GetS32(pSSM, &pThis->v2x6);
+
+    SSMR3GetU8 (pSSM, &pThis->csp_param);
+    SSMR3GetU8 (pSSM, &pThis->csp_value);
+    SSMR3GetU8 (pSSM, &pThis->csp_mode);
+    SSMR3GetU8 (pSSM, &pThis->csp_param);   /* Bug compatible! */
+    SSMR3GetMem(pSSM, pThis->csp_regs, 256);
+    SSMR3GetU8 (pSSM, &pThis->csp_index);
+    SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
+    SSMR3GetS32(pSSM, &pThis->csp_reg83r);
+    SSMR3GetS32(pSSM, &pThis->csp_reg83w);
+
+    SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
+    SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
+    SSMR3GetU8 (pSSM, &pThis->test_reg);
+    SSMR3GetU8 (pSSM, &pThis->last_read_byte);
+
+    SSMR3GetS32(pSSM, &pThis->nzero);
+    SSMR3GetS32(pSSM, &pThis->left_till_irq);
+    SSMR3GetS32(pSSM, &pThis->dma_running);
+    SSMR3GetS32(pSSM, &pThis->bytes_per_second);
+    SSMR3GetS32(pSSM, &pThis->align);
+
+    SSMR3GetS32(pSSM, &pThis->mixer_nreg);
+    SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
+
+#if 0
+    PSB16DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        if (pDrv->Out.pStrmOut)
+        {
+            pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
+            pDrv->Out.pStrmOut = NULL;
+        }
+    }
+#endif
+
+    if (pThis->dma_running)
+    {
+        if (pThis->freq)
+        {
+            PDMAUDIOSTREAMCFG streamCfg;
+            streamCfg.uHz           = pThis->freq;
+            streamCfg.cChannels     = 1 << pThis->fmt_stereo;
+            streamCfg.enmFormat     = pThis->fmt;
+            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+            int rc = sb16OpenOut(pThis, &streamCfg);
+            AssertRC(rc);
+        }
+
+        sb16Control(pThis, 1);
+        sb16SpeakerControl(pThis, pThis->speaker);
+    }
+
+    /* Update the master (mixer) and PCM out volumes. */
+    sb16SetMasterVolume(pThis);
+    sb16SetPcmOutVolume(pThis);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
+{
+    RT_NOREF(uPass);
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    SSMR3PutS32(pSSM, pThis->irqCfg);
+    SSMR3PutS32(pSSM, pThis->dmaCfg);
+    SSMR3PutS32(pSSM, pThis->hdmaCfg);
+    SSMR3PutS32(pSSM, pThis->portCfg);
+    SSMR3PutS32(pSSM, pThis->verCfg);
+    return VINF_SSM_DONT_CALL_AGAIN;
+}
+
+static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+{
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    sb16LiveExec(pDevIns, pSSM, 0);
+    sb16Save(pSSM, pThis);
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    AssertMsgReturn(    uVersion == SB16_SAVE_STATE_VERSION
+                    ||  uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
+                    ("%u\n", uVersion),
+                    VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
+    if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
+    {
+        int32_t irq;
+        SSMR3GetS32 (pSSM, &irq);
+        int32_t dma;
+        SSMR3GetS32 (pSSM, &dma);
+        int32_t hdma;
+        SSMR3GetS32 (pSSM, &hdma);
+        int32_t port;
+        SSMR3GetS32 (pSSM, &port);
+        int32_t ver;
+        int rc = SSMR3GetS32 (pSSM, &ver);
+        AssertRCReturn (rc, rc);
+
+        if (   irq  != pThis->irqCfg
+            || dma  != pThis->dmaCfg
+            || hdma != pThis->hdmaCfg
+            || port != pThis->portCfg
+            || ver  != pThis->verCfg)
+        {
+            return SSMR3SetCfgError(pSSM, RT_SRC_POS,
+                                    N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
+                                    irq,  pThis->irqCfg,
+                                    dma,  pThis->dmaCfg,
+                                    hdma, pThis->hdmaCfg,
+                                    port, pThis->portCfg,
+                                    ver,  pThis->verCfg);
+        }
+    }
+
+    if (uPass != SSM_PASS_FINAL)
+        return VINF_SUCCESS;
+
+    sb16Load(pSSM, pThis, uVersion);
+    return VINF_SUCCESS;
+}
+
+static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    int rc = VINF_SUCCESS;
+
+    PSB16DRIVER pDrv;
+    uint8_t uLUN = 0;
+
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        char *pszDesc;
+        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        int rc2 = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+        LogFlowFunc(("LUN#%RU8: Created output with rc=%Rrc\n", uLUN, rc));
+        if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
+        {
+            AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
+            rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
+                                        pDrv->pConnector, pDrv->Out.pStrmOut,
+                                        0 /* uFlags */,
+                                        &pDrv->Out.phStrmOut);
+        }
+
+        RTStrFree(pszDesc);
+
+        if (RT_FAILURE(rc2))
+        {
+            if (RT_SUCCESS(rc))
+                rc = rc2;
+            break;
+        }
+
+        uLUN++;
+    }
+
+    /* Ensure volume gets propagated. */
+    AudioMixerInvalidate(pThis->pMixer);
+
+    return rc;
+}
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnReset}
+ */
+static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
+{
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    /* Bring back the device to initial state, and especially make
+     * sure there's no interrupt or DMA activity.
+     */
+    PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
+
+    pThis->mixer_regs[0x82] = 0;
+    pThis->csp_regs[5]      = 1;
+    pThis->csp_regs[9]      = 0xf8;
+
+    pThis->dma_auto = 0;
+    pThis->in_index = 0;
+    pThis->out_data_len = 0;
+    pThis->left_till_irq = 0;
+    pThis->needed_bytes = 0;
+    pThis->block_size = -1;
+    pThis->nzero = 0;
+    pThis->highspeed = 0;
+    pThis->v2x6 = 0;
+    pThis->cmd = -1;
+
+    sb16MixerReset(pThis);
+    sb16SpeakerControl(pThis, 0);
+    sb16Control(pThis, 0);
+    sb16ResetLegacy(pThis);
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
+{
+    PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
+    Assert(&pThis->IBase == pInterface);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
+    return NULL;
+}
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnDestruct}
+ */
+static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
+{
+    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    PSB16DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+        pDrv->Out.phStrmOut = NULL;
+
+    pThis->pSinkOutput = NULL;
+
+    if (pThis->pMixer)
+    {
+        AudioMixerDestroy(pThis->pMixer);
+        pThis->pMixer = NULL;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
+{
+    RT_NOREF(iInstance);
+    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+
+    /*
+     * Validations.
+     */
+    Assert(iInstance == 0);
+    if (!CFGMR3AreValuesValid(pCfg,
+                              "IRQ\0"
+                              "DMA\0"
+                              "DMA16\0"
+                              "Port\0"
+                              "Version\0"
+                              "TimerHz\0"))
+        return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
+                                N_("Invalid configuration for SB16 device"));
+
+    /*
+     * Read config data.
+     */
+    int rc = CFGMR3QuerySIntDef(pCfg, "IRQ", &pThis->irq, 5);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("SB16 configuration error: Failed to get the \"IRQ\" value"));
+    pThis->irqCfg  = pThis->irq;
+
+    rc = CFGMR3QuerySIntDef(pCfg, "DMA", &pThis->dma, 1);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("SB16 configuration error: Failed to get the \"DMA\" value"));
+    pThis->dmaCfg  = pThis->dma;
+
+    rc = CFGMR3QuerySIntDef(pCfg, "DMA16", &pThis->hdma, 5);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("SB16 configuration error: Failed to get the \"DMA16\" value"));
+    pThis->hdmaCfg = pThis->hdma;
+
+    RTIOPORT Port;
+    rc = CFGMR3QueryPortDef(pCfg, "Port", &Port, 0x220);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("SB16 configuration error: Failed to get the \"Port\" value"));
+    pThis->port    = Port;
+    pThis->portCfg = Port;
+
+    uint16_t u16Version;
+    rc = CFGMR3QueryU16Def(pCfg, "Version", &u16Version, 0x0405);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("SB16 configuration error: Failed to get the \"Version\" value"));
+
+#ifndef VBOX_WITH_AUDIO_CALLBACKS
+    uint16_t uTimerHz;
+    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
+#endif
+
+    pThis->ver     = u16Version;
+    pThis->verCfg  = u16Version;
+
+    /*
+     * Init instance data.
+     */
+    pThis->pDevInsR3               = pDevIns;
+    pThis->IBase.pfnQueryInterface = sb16QueryInterface;
+    pThis->cmd                     = -1;
+
+    pThis->mixer_regs[0x80]        = magic_of_irq (pThis->irq);
+    pThis->mixer_regs[0x81]        = (1 << pThis->dma) | (1 << pThis->hdma);
+    pThis->mixer_regs[0x82]        = 2 << 5;
+
+    pThis->csp_regs[5]             = 1;
+    pThis->csp_regs[9]             = 0xf8;
+
+    RTListInit(&pThis->lstDrv);
+
+    sb16MixerReset(pThis);
+
+    /*
+     * Create timer(s), register & attach stuff.
+     */
+    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
+                                TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
+    if (RT_FAILURE(rc))
+        AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
+
+    rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04,  2, pThis,
+                                 mixer_write, mixer_read, NULL, NULL, "SB16");
+    if (RT_FAILURE(rc))
+        return rc;
+    rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
+                                 dsp_write, dsp_read, NULL, NULL, "SB16");
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
+    if (RT_FAILURE(rc))
+        return rc;
+    rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    pThis->can_write = 1;
+
+    rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Attach driver.
+     */
+    uint8_t uLUN;
+    for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
+    {
+        LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
+        rc = sb16AttachInternal(pDevIns, NULL /* pDrv */, uLUN, 0 /* fFlags */);
+        if (RT_FAILURE(rc))
+        {
+            if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
+                rc = VINF_SUCCESS;
+            else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
+            {
+                sb16Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
+                PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
+                        N_("No audio devices could be opened. Selecting the NULL audio backend "
+                           "with the consequence that no sound is audible"));
+                /* attaching to the NULL audio backend will never fail */
+                rc = VINF_SUCCESS;
+            }
+            break;
+        }
+    }
+
+    LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
+
+    sb16ResetLegacy(pThis);
+
+    PSB16DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        /*
+         * Only primary drivers are critical for the VM to run. Everything else
+         * might not worth showing an own error message box in the GUI.
+         */
+        if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
+            continue;
+
+        PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
+        AssertPtr(pCon);
+
+        /* Note: No input streams available for SB16 yet. */
+        bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
+        if (!fValidOut)
+        {
+            LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
+
+            sb16ResetLegacy(pThis);
+            sb16Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
+
+            PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
+                N_("No audio devices could be opened. Selecting the NULL audio backend "
+                   "with the consequence that no sound is audible"));
+        }
+    }
+
+#ifndef VBOX_WITH_AUDIO_CALLBACKS
+    if (RT_SUCCESS(rc))
+    {
+        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
+                                    TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
+        if (RT_FAILURE(rc))
+            AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
+        else
+        {
+            pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
+            pThis->uTimerTSIO    = TMTimerGet(pThis->pTimerIO);
+            LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
+
+            /* Fire off timer. */
+            TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
+        }
+    }
+#else
+    if (RT_SUCCESS(rc))
+    {
+        /** @todo Merge this callback registration with the validation block above once
+         *  this becomes the standard. */
+        PSB16DRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+        {
+            /* Only register primary driver.
+             * The device emulation does the output multiplexing then. */
+            if (pDrv->Flags != PDMAUDIODRVFLAG_PRIMARY)
+                continue;
+
+            PDMAUDIOCALLBACK AudioCallbacks[2];
+
+            SB16CALLBACKCTX Ctx = { pThis, pDrv };
+
+            AudioCallbacks[0].enmType     = PDMAUDIOCALLBACKTYPE_INPUT;
+            AudioCallbacks[0].pfnCallback = sb16CallbackInput;
+            AudioCallbacks[0].pvCtx       = &Ctx;
+            AudioCallbacks[0].cbCtx       = sizeof(SB16CALLBACKCTX);
+
+            AudioCallbacks[1].enmType     = PDMAUDIOCALLBACKTYPE_OUTPUT;
+            AudioCallbacks[1].pfnCallback = sb16CallbackOutput;
+            AudioCallbacks[1].pvCtx       = &Ctx;
+            AudioCallbacks[1].cbCtx       = sizeof(SB16CALLBACKCTX);
+
+            rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
+            if (RT_FAILURE(rc))
+                break;
+        }
+    }
+#endif
+
+    return VINF_SUCCESS;
+}
+
+const PDMDEVREG g_DeviceSB16 =
+{
+    /* u32Version */
+    PDM_DEVREG_VERSION,
+    /* szName */
+    "sb16",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Sound Blaster 16 Controller",
+    /* fFlags */
+    PDM_DEVREG_FLAGS_DEFAULT_BITS,
+    /* fClass */
+    PDM_DEVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    1,
+    /* cbInstance */
+    sizeof(SB16STATE),
+    /* pfnConstruct */
+    sb16Construct,
+    /* pfnDestruct */
+    sb16Destruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnMemSetup */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    sb16DevReset,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    sb16Attach,
+    /* pfnDetach */
+    sb16Detach,
+    /* pfnQueryInterface */
+    NULL,
+    /* pfnInitComplete */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32VersionEnd */
+    PDM_DEVREG_VERSION
+};
diff --git a/src/VBox/Devices/Audio_50/DrvAudio.cpp b/src/VBox/Devices/Audio_50/DrvAudio.cpp
new file mode 100644
index 0000000..5385be1
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvAudio.cpp
@@ -0,0 +1,2627 @@
+/* $Id: DrvAudio.cpp $ */
+/** @file
+ * Intermediate audio driver header.
+ *
+ * @remarks Intermediate audio driver for connecting the audio device emulation
+ *          with the host backend.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: audio.c from QEMU AUDIO subsystem.
+ *
+ * QEMU Audio subsystem
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define LOG_GROUP LOG_GROUP_DRV_AUDIO
+#include <VBox/log.h>
+#include <VBox/vmm/pdm.h>
+#include <VBox/err.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+#include <iprt/alloc.h>
+#include <iprt/asm-math.h>
+#include <iprt/assert.h>
+#include <iprt/circbuf.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+
+#include "VBoxDD.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+typedef struct fixed_settings
+{
+    int enabled;
+    int cStreams;
+    int greedy;
+    PDMAUDIOSTREAMCFG settings;
+} fixed_settings;
+
+static struct {
+    struct fixed_settings fixed_out;
+    struct fixed_settings fixed_in;
+    union {
+        int hz;
+        int64_t ticks;
+    } period;
+    int plive;
+} conf = {
+
+    /* Fixed output settings. */
+    {                           /* DAC fixed settings */
+        1,                      /* enabled */
+        1,                      /* cStreams */
+        1,                      /* greedy */
+        {
+            44100,              /* freq */
+            2,                  /* nchannels */
+            AUD_FMT_S16,        /* fmt */
+            PDMAUDIOHOSTENDIANNESS
+        }
+    },
+
+    /* Fixed input settings. */
+    {                           /* ADC fixed settings */
+        1,                      /* enabled */
+        2,                      /* cStreams */
+        1,                      /* greedy */
+        {
+            44100,              /* freq */
+            2,                  /* nchannels */
+            AUD_FMT_S16,        /* fmt */
+            PDMAUDIOHOSTENDIANNESS
+        }
+    },
+
+    { 200 },                    /* frequency (in Hz) */
+    0,                          /* plive */ /** @todo Disable pending live? */
+};
+
+static int drvAudioDestroyGstIn(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMIN pGstStrmIn);
+
+static int drvAudioAllocHstIn(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOHSTSTRMIN *ppHstStrmIn);
+static int drvAudioDestroyHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+
+int drvAudioAddHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+
+    int rc;
+    if (   conf.fixed_out.enabled /** @todo Get rid of these settings! */
+        && conf.fixed_out.greedy)
+    {
+        rc = drvAudioAllocHstOut(pThis, pszName, pCfg, &pHstStrmOut);
+    }
+    else
+        rc = VERR_NOT_FOUND;
+
+    if (RT_FAILURE(rc))
+    {
+        pHstStrmOut = drvAudioFindSpecificOut(pThis, NULL, pCfg);
+        if (!pHstStrmOut)
+        {
+            rc = drvAudioAllocHstOut(pThis, pszName, pCfg, &pHstStrmOut);
+            if (RT_FAILURE(rc))
+                pHstStrmOut = drvAudioFindAnyHstOut(pThis, NULL /* pHstStrmOut */);
+        }
+
+        rc = pHstStrmOut ? VINF_SUCCESS : rc;
+    }
+
+    if (RT_SUCCESS(rc))
+        *ppHstStrmOut = pHstStrmOut;
+
+    return rc;
+}
+
+static PDMAUDIOFMT drvAudioGetConfFormat(PCFGMNODE pCfgHandle, const char *pszKey,
+                                         PDMAUDIOFMT enmDefault, bool *pfDefault)
+{
+    if (   pCfgHandle == NULL
+        || pszKey == NULL)
+    {
+        *pfDefault = true;
+        return enmDefault;
+    }
+
+    char *pszValue = NULL;
+    int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszKey, &pszValue);
+    if (RT_FAILURE(rc))
+    {
+        *pfDefault = true;
+        return enmDefault;
+    }
+
+    PDMAUDIOFMT fmt = drvAudioHlpStringToFormat(pszValue);
+    if (fmt == AUD_FMT_INVALID)
+    {
+         *pfDefault = true;
+        return enmDefault;
+    }
+
+    *pfDefault = false;
+    return fmt;
+}
+
+static int drvAudioGetConfInt(PCFGMNODE pCfgHandle, const char *pszKey,
+                              int iDefault, bool *pfDefault)
+{
+
+    if (   pCfgHandle == NULL
+        || pszKey == NULL)
+    {
+        *pfDefault = true;
+        return iDefault;
+    }
+
+    uint64_t u64Data = 0;
+    int rc = CFGMR3QueryInteger(pCfgHandle, pszKey, &u64Data);
+    if (RT_FAILURE(rc))
+    {
+        *pfDefault = true;
+        return iDefault;
+
+    }
+
+    *pfDefault = false;
+    return u64Data;
+}
+
+static const char *drvAudioGetConfStr(PCFGMNODE pCfgHandle, const char *pszKey,
+                                      const char *pszDefault, bool *pfDefault)
+{
+    if (   pCfgHandle == NULL
+        || pszKey == NULL)
+    {
+        *pfDefault = true;
+        return pszDefault;
+    }
+
+    char *pszValue = NULL;
+    int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszKey, &pszValue);
+    if (RT_FAILURE(rc))
+    {
+        *pfDefault = true;
+        return pszDefault;
+    }
+
+    *pfDefault = false;
+    return pszValue;
+}
+
+static int drvAudioProcessOptions(PCFGMNODE pCfgHandle, const char *pszPrefix, struct audio_option *opt)
+{
+    AssertPtrReturn(pCfgHandle, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
+    AssertPtrReturn(opt, VERR_INVALID_POINTER);
+
+    PCFGMNODE pCfgChildHandle = NULL;
+    PCFGMNODE pCfgChildChildHandle = NULL;
+
+   /* If pCfgHandle is NULL, let NULL be passed to get int and get string functions..
+    * The getter function will return default values.
+    */
+    if (pCfgHandle != NULL)
+    {
+       /* If its audio general setting, need to traverse to one child node.
+        * /Devices/ichac97/0/LUN#0/Config/Audio
+        */
+       if(!strncmp(pszPrefix, "AUDIO", 5)) /** @todo Use a \#define */
+       {
+            pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle);
+            if(pCfgChildHandle)
+                pCfgHandle = pCfgChildHandle;
+        }
+        else
+        {
+            /* If its driver specific configuration , then need to traverse two level deep child
+             * child nodes. for eg. in case of DirectSoundConfiguration item
+             * /Devices/ichac97/0/LUN#0/Config/Audio/DirectSoundConfig
+             */
+            pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle);
+            if (pCfgChildHandle)
+            {
+                pCfgChildChildHandle = CFGMR3GetFirstChild(pCfgChildHandle);
+                if (pCfgChildChildHandle)
+                    pCfgHandle = pCfgChildChildHandle;
+            }
+        }
+    }
+
+    for (; opt->name; opt++)
+    {
+        LogFlowFunc(("Option value pointer for `%s' is not set\n",
+                     opt->name));
+        if (!opt->valp) {
+            LogFlowFunc(("Option value pointer for `%s' is not set\n",
+                   opt->name));
+            continue;
+        }
+
+        bool fUseDefault;
+
+        switch (opt->tag)
+        {
+            case AUD_OPT_BOOL:
+            case AUD_OPT_INT:
+            {
+                int *intp = (int *)opt->valp;
+                *intp = drvAudioGetConfInt(pCfgHandle, opt->name, *intp, &fUseDefault);
+
+                break;
+            }
+
+            case AUD_OPT_FMT:
+            {
+                PDMAUDIOFMT *fmtp = (PDMAUDIOFMT *)opt->valp;
+                *fmtp = drvAudioGetConfFormat(pCfgHandle, opt->name, *fmtp, &fUseDefault);
+
+                break;
+            }
+
+            case AUD_OPT_STR:
+            {
+                const char **strp = (const char **)opt->valp;
+                *strp = drvAudioGetConfStr(pCfgHandle, opt->name, *strp, &fUseDefault);
+
+                break;
+            }
+
+            default:
+                LogFlowFunc(("Bad value tag for option `%s' - %d\n", opt->name, opt->tag));
+                fUseDefault = false;
+                break;
+        }
+
+        if (!opt->overridenp)
+            opt->overridenp = &opt->overriden;
+
+        *opt->overridenp = !fUseDefault;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static bool drvAudioStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
+{
+    bool fValid = (   pCfg->cChannels == 1
+                   || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
+
+    fValid |= (   pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
+               || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
+
+    if (fValid)
+    {
+        switch (pCfg->enmFormat)
+        {
+            case AUD_FMT_S8:
+            case AUD_FMT_U8:
+            case AUD_FMT_S16:
+            case AUD_FMT_U16:
+            case AUD_FMT_S32:
+            case AUD_FMT_U32:
+                break;
+            default:
+                fValid = false;
+                break;
+        }
+    }
+
+    /** @todo Check for defined frequencies supported. */
+    fValid |= pCfg->uHz > 0;
+
+#ifdef DEBUG
+    drvAudioStreamCfgPrint(pCfg);
+#endif
+
+    LogFlowFunc(("pCfg=%p, fValid=%RTbool\n", pCfg, fValid));
+    return fValid;
+}
+
+/**
+ * Clears a sample buffer by the given amount of audio samples.
+ *
+ * @return  IPRT status code.
+ * @param   pPCMProps               PCM properties to use for the buffer to clear.
+ * @param   pvBuf                   Buffer to clear.
+ * @param   cbBuf                   Size (in bytes) of the buffer.
+ * @param   cSamples                Number of audio samples to clear in the buffer.
+ */
+void DrvAudioClearBuf(PPDMPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cSamples)
+{
+    AssertPtrReturnVoid(pPCMProps);
+    AssertPtrReturnVoid(pvBuf);
+
+    if (!cbBuf || !cSamples)
+        return;
+
+    Log2Func(("pPCMInfo=%p, pvBuf=%p, cSamples=%RU32, fSigned=%RTbool, cBits=%RU8, cShift=%RU8\n",
+              pPCMProps, pvBuf, cSamples, pPCMProps->fSigned, pPCMProps->cBits, pPCMProps->cShift));
+
+    if (pPCMProps->fSigned)
+    {
+        memset(pvBuf, 0, cSamples << pPCMProps->cShift);
+    }
+    else
+    {
+        switch (pPCMProps->cBits)
+        {
+            case 8:
+            {
+                memset(pvBuf, 0x80, cSamples << pPCMProps->cShift);
+                break;
+            }
+
+            case 16:
+            {
+                uint16_t *p = (uint16_t *)pvBuf;
+                int shift = pPCMProps->cChannels - 1;
+                short s = INT16_MAX;
+
+                if (pPCMProps->fSwapEndian)
+                    s = RT_BSWAP_U16(s);
+
+                for (unsigned i = 0; i < cSamples << shift; i++)
+                    p[i] = s;
+
+                break;
+            }
+
+            case 32:
+            {
+                uint32_t *p = (uint32_t *)pvBuf;
+                int shift = pPCMProps->cChannels - 1;
+                int32_t s = INT32_MAX;
+
+                if (pPCMProps->fSwapEndian)
+                    s = RT_BSWAP_U32(s);
+
+                for (unsigned i = 0; i < cSamples << shift; i++)
+                    p[i] = s;
+
+                break;
+            }
+
+            default:
+            {
+                AssertMsgFailed(("Invalid bits: %RU8\n", pPCMProps->cBits));
+                break;
+            }
+        }
+    }
+}
+
+static int drvAudioControlHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    int rc = RTCritSectEnter(&pHstStrmIn->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        {
+            if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+            {
+                rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_ENABLE);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStrmIn->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+                }
+                else
+                    LogFlowFunc(("Backend reported an error when opening input stream, rc=%Rrc\n", rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        {
+            if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+            {
+                rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_DISABLE);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStrmIn->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE; /* Clear all. */
+                    AudioMixBufClear(&pHstStrmIn->MixBuf);
+                }
+                else
+                    LogFlowFunc(("Backend vetoed closing output stream, rc=%Rrc\n", rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
+            {
+                Assert(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+                rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_PAUSE);
+                if (RT_SUCCESS(rc))
+                {
+                    LogFunc(("[%s] Pausing stream\n", pHstStrmIn->MixBuf.pszName));
+                    pHstStrmIn->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
+                }
+                else
+                    LogFlowFunc(("Backend vetoed pausing input stream, rc=%Rrc\n", rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
+            {
+                Assert(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+                rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_RESUME);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStrmIn->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+                    LogFunc(("[%s] Resumed stream\n", pHstStrmIn->MixBuf.pszName));
+                }
+                else
+                    LogFlowFunc(("Backend vetoed resuming input stream, rc=%Rrc\n", rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    int rc2 = RTCritSectLeave(&pHstStrmIn->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+static int drvAudioControlHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    int rc = RTCritSectEnter(&pHstStrmOut->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        {
+            if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+            {
+                rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
+                if (RT_SUCCESS(rc))
+                {
+                    Assert(!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
+                    pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+                    LogFunc(("[%s] Enabled stream\n", pHstStrmOut->MixBuf.pszName));
+                }
+                else
+                    LogFlowFunc(("[%s] Backend reported an error when enabling output stream, rc=%Rrc\n",
+                                 pHstStrmOut->MixBuf.pszName, rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        {
+            if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+            {
+                rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStrmOut->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE; /* Clear all. */
+                    AudioMixBufClear(&pHstStrmOut->MixBuf);
+
+                    LogFunc(("[%s] Disabled stream\n", pHstStrmOut->MixBuf.pszName));
+                }
+                else
+                    LogFlowFunc(("[%s] Backend vetoed disabling output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
+            {
+                Assert(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+                rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_PAUSE);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
+                    LogFunc(("[%s] Pausing stream\n", pHstStrmOut->MixBuf.pszName));
+                }
+                else
+                    LogFlowFunc(("[%s] Backend vetoed pausing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
+            {
+                Assert(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+                rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_RESUME);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+                    LogFunc(("[%s] Resumed stream\n", pHstStrmOut->MixBuf.pszName));
+                }
+                else
+                    LogFlowFunc(("[%s] Backend vetoed resuming output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
+            }
+            else
+                rc = VINF_SUCCESS;
+
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    int rc2 = RTCritSectLeave(&pHstStrmOut->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+int drvAudioDestroyHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("%s\n", pHstStrmOut->MixBuf.pszName));
+
+    int rc;
+    if (RTListIsEmpty(&pHstStrmOut->lstGstStrmOut))
+    {
+        rc = pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
+        if (RT_SUCCESS(rc))
+        {
+            drvAudioHstOutFreeRes(pHstStrmOut);
+
+            /* Remove from driver instance list. */
+            RTListNodeRemove(&pHstStrmOut->Node);
+
+            if (RTCritSectIsInitialized(&pHstStrmOut->CritSect))
+            {
+                int rc2 = RTCritSectDelete(&pHstStrmOut->CritSect);
+                AssertRC(rc2);
+            }
+
+            RTMemFree(pHstStrmOut);
+            pThis->cFreeOutputStreams++;
+            return VINF_SUCCESS;
+        }
+    }
+    else
+    {
+        rc = VERR_ACCESS_DENIED;
+        LogFlowFunc(("[%s] Still is being used, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
+    }
+
+    return rc;
+}
+
+int drvAudioDestroyGstOut(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    if (!pGstStrmOut)
+        return VINF_SUCCESS;
+
+    if (pGstStrmOut->State.cRefs > 1) /* Do other objects still have a reference to it? Bail out. */
+        return VERR_WRONG_ORDER;
+
+    drvAudioGstOutFreeRes(pGstStrmOut);
+
+    if (pGstStrmOut->pHstStrmOut)
+    {
+        /* Unregister from parent first. */
+        RTListNodeRemove(&pGstStrmOut->Node);
+
+        /* Try destroying the associated host output stream. This could
+         * be skipped if there are other guest output streams with this
+         * host stream. */
+        drvAudioDestroyHstOut(pThis, pGstStrmOut->pHstStrmOut);
+    }
+
+    RTMemFree(pGstStrmOut);
+
+    return VINF_SUCCESS;
+}
+
+PPDMAUDIOHSTSTRMIN drvAudioFindNextHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    if (pHstStrmIn)
+    {
+        if (RTListNodeIsLast(&pThis->lstHstStrmIn, &pHstStrmIn->Node))
+            return NULL;
+
+        return RTListNodeGetNext(&pHstStrmIn->Node, PDMAUDIOHSTSTRMIN, Node);
+    }
+
+    return RTListGetFirst(&pThis->lstHstStrmIn, PDMAUDIOHSTSTRMIN, Node);
+}
+
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEnabledHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
+        if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+            return pHstStrmIn;
+
+    return NULL;
+}
+
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEqHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                           PPDMAUDIOSTREAMCFG pCfg)
+{
+    while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
+        if (drvAudioPCMPropsAreEqual(&pHstStrmIn->Props, pCfg))
+            return pHstStrmIn;
+
+    return NULL;
+}
+
+static int drvAudioHstInAdd(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PDMAUDIORECSOURCE enmRecSource,
+                            PPDMAUDIOHSTSTRMIN *ppHstStrmIn)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+    AssertPtrReturn(ppHstStrmIn, VERR_INVALID_POINTER);
+
+    PPDMAUDIOHSTSTRMIN pHstStrmIn;
+    int rc = drvAudioAllocHstIn(pThis, pszName, pCfg, enmRecSource, &pHstStrmIn);
+    if (RT_SUCCESS(rc))
+        *ppHstStrmIn = pHstStrmIn;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int drvAudioGstOutInit(PPDMAUDIOGSTSTRMOUT pGstStrmOut, PPDMAUDIOHSTSTRMOUT pHostStrmOut,
+                       const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pGstStrmOut,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostStrmOut, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName,      VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,         VERR_INVALID_POINTER);
+
+    int rc = DrvAudioStreamCfgToProps(pCfg, &pGstStrmOut->Props);
+    if (RT_SUCCESS(rc))
+    {
+        char *pszTemp;
+        if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
+            return VERR_NO_MEMORY;
+
+        rc = AudioMixBufInit(&pGstStrmOut->MixBuf, pszTemp, &pGstStrmOut->Props, AudioMixBufSize(&pHostStrmOut->MixBuf));
+        if (RT_SUCCESS(rc))
+            rc = AudioMixBufLinkTo(&pGstStrmOut->MixBuf, &pHostStrmOut->MixBuf);
+
+        RTStrFree(pszTemp);
+
+        if (RT_SUCCESS(rc))
+        {
+            pGstStrmOut->State.cRefs   = 1;
+            pGstStrmOut->State.fActive = false;
+            pGstStrmOut->State.fEmpty  = true;
+
+            pGstStrmOut->State.pszName = RTStrDup(pszName);
+            if (!pGstStrmOut->State.pszName)
+                return VERR_NO_MEMORY;
+
+            pGstStrmOut->pHstStrmOut = pHostStrmOut;
+        }
+    }
+
+    LogFlowFunc(("pszName=%s, rc=%Rrc\n", pszName, rc));
+    return rc;
+}
+
+int drvAudioAllocHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    if (!pThis->cFreeOutputStreams)
+    {
+        LogFlowFunc(("Maximum number of host output streams reached\n"));
+        return VERR_NO_MORE_HANDLES;
+    }
+
+    /* Validate backend configuration. */
+    if (!pThis->BackendCfg.cbStreamOut)
+    {
+        LogFlowFunc(("Backend output configuration not valid, bailing out\n"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = (PPDMAUDIOHSTSTRMOUT)RTMemAllocZ(pThis->BackendCfg.cbStreamOut);
+    if (!pHstStrmOut)
+    {
+        LogFlowFunc(("Error allocating host output stream with %zu bytes\n",
+                     pThis->BackendCfg.cbStreamOut));
+        return VERR_NO_MEMORY;
+    }
+
+    int rc;
+    bool fInitialized = false;
+
+    do
+    {
+        RTListInit(&pHstStrmOut->lstGstStrmOut);
+
+        /* Make the acquired configuration the requested configuration by default. */
+        PDMAUDIOSTREAMCFG CfgAcq;
+        memcpy(&CfgAcq, pCfg, sizeof(PDMAUDIOSTREAMCFG));
+
+        uint32_t cSamples;
+        rc = pThis->pHostDrvAudio->pfnInitOut(pThis->pHostDrvAudio, pHstStrmOut,
+                                              pCfg /* pCfgReq */, &CfgAcq /* pCfgAcq */,
+                                              &cSamples);
+        if (RT_FAILURE(rc))
+        {
+            LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
+            break;
+        }
+
+        fInitialized = true;
+
+        char *pszTemp;
+        if (RTStrAPrintf(&pszTemp, "%s (Host)", pszName) <= 0)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+#ifdef DEBUG
+        LogFunc(("%s: Requested format:\n", pszTemp));
+        drvAudioStreamCfgPrint(pCfg);
+        LogFunc(("%s: Acquired format:\n",  pszTemp));
+        drvAudioStreamCfgPrint(&CfgAcq);
+#else
+        LogRel2(("Audio: Acquired output format for '%s': %RU32Hz, %s, %RU8 %s\n",
+                 pszTemp, CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
+                 CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
+#endif
+        rc = DrvAudioStreamCfgToProps(&CfgAcq, &pHstStrmOut->Props);
+        if (RT_SUCCESS(rc))
+        {
+            rc = AudioMixBufInit(&pHstStrmOut->MixBuf, pszTemp, &pHstStrmOut->Props, cSamples);
+            if (RT_SUCCESS(rc))
+                rc = RTCritSectInit(&pHstStrmOut->CritSect);
+
+            if (RT_SUCCESS(rc))
+            {
+                RTListPrepend(&pThis->lstHstStrmOut, &pHstStrmOut->Node);
+                pThis->cFreeOutputStreams--;
+            }
+        }
+
+        RTStrFree(pszTemp);
+
+    } while (0);
+
+    if (RT_FAILURE(rc))
+    {
+        if (fInitialized)
+        {
+            int rc2 = pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
+            AssertRC(rc2);
+        }
+
+        drvAudioHstOutFreeRes(pHstStrmOut);
+        RTMemFree(pHstStrmOut);
+    }
+    else
+        *ppHstStrmOut = pHstStrmOut;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int drvAudioCreateStreamPairOut(PDRVAUDIO pThis, const char *pszName,
+                                PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    /*
+     * Try figuring out which audio stream configuration this backend
+     * should use. If fixed output is enabled the backend will be tied
+     * to a fixed rate (in Hz, among other parameters), regardless of
+     * what the backend could do else.
+     */
+    PPDMAUDIOSTREAMCFG pBackendCfg;
+    if (conf.fixed_out.enabled)
+        pBackendCfg = &conf.fixed_out.settings;
+    else
+        pBackendCfg = pCfg;
+
+    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("Using fixed audio output settings: %RTbool\n",
+                 RT_BOOL(conf.fixed_out.enabled)));
+
+    PPDMAUDIOGSTSTRMOUT pGstStrmOut =
+        (PPDMAUDIOGSTSTRMOUT)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMOUT));
+    if (!pGstStrmOut)
+    {
+        LogFlowFunc(("Failed to allocate memory for guest output stream \"%s\"\n", pszName));
+        return VERR_NO_MEMORY;
+    }
+
+    /*
+     * The host stream always will get the backend audio stream configuration.
+     */
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut;
+    int rc = drvAudioAddHstOut(pThis, pszName, pBackendCfg, &pHstStrmOut);
+    if (RT_FAILURE(rc))
+    {
+        LogFlowFunc(("Error adding host output stream \"%s\", rc=%Rrc\n", pszName, rc));
+
+        RTMemFree(pGstStrmOut);
+        return rc;
+    }
+
+    /*
+     * The guest stream always will get the audio stream configuration told
+     * by the device emulation (which in turn was/could be set by the guest OS).
+     */
+    rc = drvAudioGstOutInit(pGstStrmOut, pHstStrmOut, pszName, pCfg);
+    if (RT_SUCCESS(rc))
+    {
+        RTListPrepend(&pHstStrmOut->lstGstStrmOut, &pGstStrmOut->Node);
+
+        if (ppGstStrmOut)
+            *ppGstStrmOut = pGstStrmOut;
+    }
+
+    if (RT_FAILURE(rc))
+        drvAudioDestroyGstOut(pThis, pGstStrmOut);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static int drvAudioCreateStreamPairIn(PDRVAUDIO pThis, const char *pszName, PDMAUDIORECSOURCE enmRecSource,
+                                      PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+
+    /*
+     * Try figuring out which audio stream configuration this backend
+     * should use for the audio input data. If fixed input is enabled
+     * the backend will be tied to a fixed rate (in Hz, among other parameters),
+     * regardless of what the backend initially wanted to use.
+     */
+    PPDMAUDIOSTREAMCFG pBackendCfg;
+    if (conf.fixed_in.enabled)
+        pBackendCfg = &conf.fixed_in.settings;
+    else
+        pBackendCfg = pCfg;
+
+    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("Using fixed audio input settings: %RTbool\n",
+                 RT_BOOL(conf.fixed_in.enabled)));
+
+    PPDMAUDIOGSTSTRMIN pGstStrmIn = (PPDMAUDIOGSTSTRMIN)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMIN));
+    if (!pGstStrmIn)
+        return VERR_NO_MEMORY;
+
+    /*
+     * The host stream always will get the backend audio stream configuration.
+     */
+    PPDMAUDIOHSTSTRMIN pHstStrmIn;
+    int rc = drvAudioHstInAdd(pThis, pszName, pBackendCfg, enmRecSource, &pHstStrmIn);
+    if (RT_FAILURE(rc))
+    {
+        LogFunc(("Failed to add host audio input stream \"%s\", rc=%Rrc\n", pszName, rc));
+
+        RTMemFree(pGstStrmIn);
+        return rc;
+    }
+
+    /*
+     * The guest stream always will get the audio stream configuration told
+     * by the device emulation (which in turn was/could be set by the guest OS).
+     */
+    rc = drvAudioGstInInit(pGstStrmIn, pHstStrmIn, pszName, pCfg);
+    if (RT_SUCCESS(rc))
+    {
+        pHstStrmIn->pGstStrmIn = pGstStrmIn;
+
+        if (ppGstStrmIn)
+            *ppGstStrmIn = pGstStrmIn;
+    }
+    else
+        drvAudioDestroyGstIn(pThis, pGstStrmIn);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Initializes a guest input stream.
+ *
+ * @return  IPRT status code.
+ * @param   pGstStrmIn          Pointer to guest stream to initialize.
+ * @param   pHstStrmIn          Pointer to host input stream to associate this guest
+ *                              stream with.
+ * @param   pszName             Pointer to stream name to use for this stream.
+ * @param   pCfg                Pointer to stream configuration to use.
+ */
+int drvAudioGstInInit(PPDMAUDIOGSTSTRMIN pGstStrmIn, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                      const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pGstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    int rc = DrvAudioStreamCfgToProps(pCfg, &pGstStrmIn->Props);
+    if (RT_SUCCESS(rc))
+    {
+        char *pszTemp;
+        if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
+            return VERR_NO_MEMORY;
+
+        rc = AudioMixBufInit(&pGstStrmIn->MixBuf, pszTemp, &pGstStrmIn->Props, AudioMixBufSize(&pHstStrmIn->MixBuf));
+        if (RT_SUCCESS(rc))
+            rc = AudioMixBufLinkTo(&pHstStrmIn->MixBuf, &pGstStrmIn->MixBuf);
+
+        RTStrFree(pszTemp);
+
+        if (RT_SUCCESS(rc))
+        {
+#ifdef DEBUG
+            drvAudioStreamCfgPrint(pCfg);
+#endif
+            pGstStrmIn->State.cRefs   = 1;
+            pGstStrmIn->State.fActive = false;
+            pGstStrmIn->State.fEmpty  = true;
+
+            pGstStrmIn->State.pszName = RTStrDup(pszName);
+            if (!pGstStrmIn->State.pszName)
+                return VERR_NO_MEMORY;
+
+            pGstStrmIn->pHstStrmIn = pHstStrmIn;
+        }
+    }
+
+    LogFlowFunc(("pszName=%s, rc=%Rrc\n", pszName, rc));
+    return rc;
+}
+
+static int drvAudioAllocHstIn(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg,
+                              PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOHSTSTRMIN *ppHstStrmIn)
+{
+    if (!pThis->cFreeInputStreams)
+    {
+        LogFlowFunc(("No more input streams free to use, bailing out\n"));
+        return VERR_NO_MORE_HANDLES;
+    }
+
+    /* Validate backend configuration. */
+    if (!pThis->BackendCfg.cbStreamIn)
+    {
+        LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    PPDMAUDIOHSTSTRMIN pHstStrmIn =
+        (PPDMAUDIOHSTSTRMIN)RTMemAllocZ(pThis->BackendCfg.cbStreamIn);
+    if (!pHstStrmIn)
+    {
+        LogFlowFunc(("Error allocating host innput stream with %RU32 bytes\n",
+                     pThis->BackendCfg.cbStreamOut));
+        return VERR_NO_MEMORY;
+    }
+
+    int rc;
+    bool fInitialized = false;
+
+    do
+    {
+        /* Make the acquired configuration the requested configuration by default. */
+        PDMAUDIOSTREAMCFG CfgAcq;
+        memcpy(&CfgAcq, pCfg, sizeof(PDMAUDIOSTREAMCFG));
+
+#ifndef DEBUG
+        LogRel2(("Audio: Requested input format: %RU32Hz, %s, %RU8 %s\n",
+                 CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
+                 CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
+#endif
+        uint32_t cSamples;
+        rc = pThis->pHostDrvAudio->pfnInitIn(pThis->pHostDrvAudio, pHstStrmIn,
+                                             pCfg /* pCfgReq */, &CfgAcq /* pCfgAcq */,
+                                             enmRecSource, &cSamples);
+        if (RT_FAILURE(rc))
+        {
+            LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
+            break;
+        }
+
+        fInitialized = true;
+
+        char *pszTemp;
+        if (RTStrAPrintf(&pszTemp, "%s (Host)", pszName) <= 0)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+#ifdef DEBUG
+        LogFunc(("%s: Requested format:\n", pszTemp));
+        drvAudioStreamCfgPrint(pCfg);
+        LogFunc(("%s: Acquired format:\n",  pszTemp));
+        drvAudioStreamCfgPrint(&CfgAcq);
+#else
+        LogRel2(("Audio: Acquired input format for '%s': %RU32Hz, %s, %RU8 %s\n",
+                 pszTemp, CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
+                 CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
+#endif
+        rc = DrvAudioStreamCfgToProps(&CfgAcq, &pHstStrmIn->Props);
+        if (RT_SUCCESS(rc))
+        {
+            rc = AudioMixBufInit(&pHstStrmIn->MixBuf, pszTemp, &pHstStrmIn->Props, cSamples);
+            if (RT_SUCCESS(rc))
+                rc = RTCritSectInit(&pHstStrmIn->CritSect);
+
+            if (RT_SUCCESS(rc))
+            {
+                RTListPrepend(&pThis->lstHstStrmIn, &pHstStrmIn->Node);
+                pThis->cFreeInputStreams--;
+            }
+        }
+
+        RTStrFree(pszTemp);
+
+    } while (0);
+
+    if (RT_FAILURE(rc))
+    {
+        if (fInitialized)
+        {
+            int rc2 = pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio,
+                                                      pHstStrmIn);
+            AssertRC(rc2);
+        }
+
+        drvAudioHstInFreeRes(pHstStrmIn);
+        RTMemFree(pHstStrmIn);
+    }
+    else
+        *ppHstStrmIn = pHstStrmIn;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Writes VM audio output data from the guest stream into the host stream.
+ * The attached host driver backend then will play out the audio in a
+ * later step then.
+ *
+ * @return  IPRT status code.
+ * @return  int
+ * @param   pThis
+ * @param   pGstStrmOut
+ * @param   pvBuf
+ * @param   cbBuf
+ * @param   pcbWritten
+ */
+static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut,
+                                       const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+{
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf,       VERR_INVALID_POINTER);
+    AssertReturn(cbBuf,          VERR_INVALID_PARAMETER);
+    /* pcbWritten is optional. */
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
+    {
+        rc = RTCritSectLeave(&pThis->CritSect);
+        AssertRC(rc);
+
+        return VERR_NOT_AVAILABLE;
+    }
+
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    AssertMsg(pGstStrmOut->pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
+              ("Writing to disabled host output stream \"%s\" not possible\n",
+              pHstStrmOut->MixBuf.pszName));
+
+    if (!AudioMixBufFreeBytes(&pGstStrmOut->MixBuf))
+    {
+        if (pcbWritten)
+            *pcbWritten = 0;
+
+        return RTCritSectLeave(&pThis->CritSect);
+    }
+
+    /*
+     * First, write data from the device emulation into our
+     * guest mixing buffer.
+     */
+    uint32_t cWritten;
+    rc = AudioMixBufWriteAt(&pGstStrmOut->MixBuf, 0 /* Offset in samples */, pvBuf, cbBuf, &cWritten);
+
+    /*
+     * Second, mix the guest mixing buffer with the host mixing
+     * buffer so that the host backend can play the data lateron.
+     */
+    uint32_t cMixed;
+    if (   RT_SUCCESS(rc)
+        && cWritten)
+    {
+        rc = AudioMixBufMixToParent(&pGstStrmOut->MixBuf, cWritten, &cMixed);
+    }
+    else
+        cMixed = 0;
+
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Return the number of samples which actually have been mixed
+         * down to the parent, regardless how much samples were written
+         * into the children buffer.
+         */
+        if (pcbWritten)
+            *pcbWritten = AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cMixed);
+    }
+
+    LogFlowFunc(("%s -> %s: Written pvBuf=%p, cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
+                 pGstStrmOut->MixBuf.pszName, pHstStrmOut->MixBuf.pszName, pvBuf, cbBuf, cWritten,
+                 AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten), cMixed, rc));
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+PPDMAUDIOHSTSTRMOUT drvAudioFindAnyHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    if (pHstStrmOut)
+    {
+        if (RTListNodeIsLast(&pThis->lstHstStrmOut, &pHstStrmOut->Node))
+            return NULL;
+
+        return RTListNodeGetNext(&pHstStrmOut->Node, PDMAUDIOHSTSTRMOUT, Node);
+    }
+
+    return RTListGetFirst(&pThis->lstHstStrmOut, PDMAUDIOHSTSTRMOUT, Node);
+}
+
+PPDMAUDIOHSTSTRMOUT drvAudioHstFindAnyEnabledOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHostStrmOut)
+{
+    while ((pHostStrmOut = drvAudioFindAnyHstOut(pThis, pHostStrmOut)))
+    {
+        if (pHostStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+            return pHostStrmOut;
+    }
+
+    return NULL;
+}
+
+PPDMAUDIOHSTSTRMOUT drvAudioFindSpecificOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                            PPDMAUDIOSTREAMCFG pCfg)
+{
+    while ((pHstStrmOut = drvAudioFindAnyHstOut(pThis, pHstStrmOut)))
+    {
+        if (drvAudioPCMPropsAreEqual(&pHstStrmOut->Props, pCfg))
+            return pHstStrmOut;
+    }
+
+    return NULL;
+}
+
+int drvAudioDestroyHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("%s\n", pHstStrmIn->MixBuf.pszName));
+
+    int rc;
+    if (!pHstStrmIn->pGstStrmIn) /* No parent anymore? */
+    {
+        rc = pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, pHstStrmIn);
+        if (RT_SUCCESS(rc))
+        {
+            drvAudioHstInFreeRes(pHstStrmIn);
+
+            if (RTCritSectIsInitialized(&pHstStrmIn->CritSect))
+            {
+                int rc2 = RTCritSectDelete(&pHstStrmIn->CritSect);
+                AssertRC(rc2);
+            }
+
+            /* Remove from driver instance list. */
+            RTListNodeRemove(&pHstStrmIn->Node);
+
+            RTMemFree(pHstStrmIn);
+            pThis->cFreeInputStreams++;
+        }
+    }
+    else
+    {
+        rc = VERR_ACCESS_DENIED;
+        LogFlowFunc(("[%s] Still is being used, rc=%Rrc\n", pHstStrmIn->MixBuf.pszName, rc));
+    }
+
+    return rc;
+}
+
+static int drvAudioDestroyGstIn(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMIN pGstStrmIn)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("%s\n", pGstStrmIn->MixBuf.pszName));
+
+    if (!pGstStrmIn)
+        return VINF_SUCCESS;
+
+    if (pGstStrmIn->State.cRefs > 1) /* Do other objects still have a reference to it? Bail out. */
+        return VERR_WRONG_ORDER;
+
+    drvAudioGstInFreeRes(pGstStrmIn);
+
+    if (pGstStrmIn->pHstStrmIn)
+    {
+        /* Unlink child. */
+        pGstStrmIn->pHstStrmIn->pGstStrmIn = NULL;
+
+        /* Try destroying the associated host input stream. This could
+         * be skipped if there are other guest input streams with this
+         * host stream. */
+        drvAudioDestroyHstIn(pThis, pGstStrmIn->pHstStrmIn);
+    }
+
+    RTMemFree(pGstStrmIn);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioQueryStatus(PPDMIAUDIOCONNECTOR pInterface,
+                                             uint32_t *pcbAvailIn, uint32_t *pcbFreeOut,
+                                             uint32_t *pcSamplesLive)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    /* pcbAvailIn is optional. */
+    /* pcbFreeOut is optional. */
+    /* pcSamplesLive is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Playback.
+     */
+    uint32_t cSamplesLive = 0;
+    uint32_t cbFreeOut    = UINT32_MAX;
+
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
+    {
+        cSamplesLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+
+        /* Has this stream marked as disabled but there still were guest streams relying
+         * on it? Check if this stream now can be closed and do so, if possible. */
+        if (   (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
+            && !cSamplesLive)
+        {
+            /* Stop playing the current (pending) stream. */
+            int rc2 = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+            if (RT_SUCCESS(rc2))
+            {
+                pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+
+                LogFunc(("[%s] Disabling stream\n", pHstStrmOut->MixBuf.pszName));
+            }
+            else
+                LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc2));
+
+            continue;
+        }
+
+        LogFlowFunc(("[%s] cSamplesLive=%RU32\n", pHstStrmOut->MixBuf.pszName, cSamplesLive));
+
+        /*
+         * No live samples to play at the moment?
+         *
+         * Tell the device emulation for each connected guest stream how many
+         * bytes are free so that the device emulation can continue writing data to
+         * these streams.
+         */
+        PPDMAUDIOGSTSTRMOUT pGstStrmOut;
+        uint32_t cbFree2 = UINT32_MAX;
+        RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
+        {
+            if (pGstStrmOut->State.fActive)
+            {
+                /* Tell the sound device emulation how many samples are free
+                 * so that it can start writing PCM data to us. */
+                cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
+                                                                AudioMixBufFree(&pGstStrmOut->MixBuf)));
+#ifdef DEBUG_andy
+                LogFlowFunc(("\t[%s] cbFreeOut=%RU32\n", pGstStrmOut->MixBuf.pszName, cbFree2));
+#endif
+            }
+        }
+
+        cbFreeOut = RT_MIN(cbFreeOut, cbFree2);
+    }
+
+    /*
+     * Recording.
+     */
+    uint32_t cbAvailIn = 0;
+
+    PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
+    while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
+    {
+        /* Call the host backend to capture the audio input data. */
+        uint32_t cSamplesCaptured;
+        int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
+                                                     &cSamplesCaptured);
+        if (RT_FAILURE(rc2))
+            continue;
+
+        PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
+        AssertPtrBreak(pGstStrmIn);
+
+        if (pGstStrmIn->State.fActive)
+        {
+            cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
+                                                          AudioMixBufMixed(&pHstStrmIn->MixBuf)));
+#ifdef DEBUG_andy
+            LogFlowFunc(("\t[%s] cbAvailIn=%RU32\n", pHstStrmIn->MixBuf.pszName, cbAvailIn));
+#endif
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (cbFreeOut == UINT32_MAX)
+            cbFreeOut = 0;
+
+        if (pcbAvailIn)
+            *pcbAvailIn = cbAvailIn;
+
+        if (pcbFreeOut)
+            *pcbFreeOut = cbFreeOut;
+
+        if (pcSamplesLive)
+            *pcSamplesLive = cSamplesLive;
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    if (RT_FAILURE(rc))
+        LogFlowFuncLeaveRC(rc);
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    /* pcSamplesPlayed is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /* Backend output (temporarily) disabled / unavailable? */
+    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
+    {
+        rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
+        AssertRC(rc);
+
+        if (!pThis->BackendCfg.cMaxHstStrmsOut)
+        {
+            int rc2 = RTCritSectLeave(&pThis->CritSect);
+            AssertRC(rc2);
+
+            return VERR_NOT_AVAILABLE;
+        }
+    }
+
+    /*
+     * Process all enabled host output streams.
+     */
+    uint32_t            cSamplesPlayedMax = 0;
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut       = NULL;
+    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
+    {
+#if 0
+        uint32_t cStreamsLive;
+        uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
+        if (!cStreamsLive)
+            cSamplesLive = 0;
+
+        /* Has this stream marked as disabled but there still were guest streams relying
+         * on it? Check if this stream now can be closed and do so, if possible. */
+        if (   pHstStrmOut->fPendingDisable
+            && !cStreamsLive)
+        {
+            /* Stop playing the current (pending) stream. */
+            int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut,
+                                                          PDMAUDIOSTREAMCMD_DISABLE);
+            if (RT_SUCCESS(rc2))
+            {
+                pHstStrmOut->fEnabled        = false;
+                pHstStrmOut->fPendingDisable = false;
+
+                LogFunc(("\t%p: Disabling stream\n", pHstStrmOut));
+            }
+            else
+                LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n",
+                         pHstStrmOut, rc2));
+
+            continue;
+        }
+#endif
+
+        uint32_t cSamplesPlayed = 0;
+        int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
+        if (RT_FAILURE(rc2))
+        {
+            rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+            AssertRC(rc2);
+        }
+        else
+            cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
+
+        LogFlowFunc(("\t[%s] cSamplesPlayed=%RU32, cSamplesPlayedMax=%RU32, rc=%Rrc\n",
+                     pHstStrmOut->MixBuf.pszName, cSamplesPlayed, cSamplesPlayedMax, rc2));
+
+        bool fNeedsCleanup = false;
+
+        PPDMAUDIOGSTSTRMOUT pGstStrmOut;
+        RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
+        {
+            if (   !pGstStrmOut->State.fActive
+                && pGstStrmOut->State.fEmpty)
+                continue;
+
+            if (AudioMixBufIsEmpty(&pGstStrmOut->MixBuf))
+            {
+                pGstStrmOut->State.fEmpty = true;
+                fNeedsCleanup |= !pGstStrmOut->State.fActive;
+            }
+        }
+
+        if (fNeedsCleanup)
+        {
+            RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
+            {
+                if (!pGstStrmOut->State.fActive)
+                    drvAudioDestroyGstOut(pThis, pGstStrmOut);
+            }
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = cSamplesPlayedMax;
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    if (RT_FAILURE(rc))
+        LogFlowFuncLeaveRC(rc);
+
+    return rc;
+}
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+static PPDMAUDIOCALLBACK drvAudioCallbackDuplicate(PPDMAUDIOCALLBACK pCB)
+{
+    PPDMAUDIOCALLBACK pCBCopy = (PPDMAUDIOCALLBACK)RTMemDup((void *)pCB, sizeof(PDMAUDIOCALLBACK));
+    if (!pCBCopy)
+        return NULL;
+
+    if (pCB->pvCtx)
+    {
+        pCBCopy->pvCtx = RTMemDup(pCB->pvCtx, pCB->cbCtx);
+        if (!pCBCopy->pvCtx)
+        {
+            RTMemFree(pCBCopy);
+            return NULL;
+        }
+
+        pCBCopy->cbCtx = pCB->cbCtx;
+    }
+
+    return pCBCopy;
+}
+
+static void drvAudioCallbackDestroy(PPDMAUDIOCALLBACK pCB)
+{
+    if (!pCB)
+        return;
+
+    RTListNodeRemove(&pCB->Node);
+    if (pCB->pvCtx)
+    {
+        Assert(pCB->cbCtx);
+        RTMemFree(pCB->pvCtx);
+    }
+    RTMemFree(pCB);
+}
+
+static DECLCALLBACK(int) drvAudioRegisterCallbacks(PPDMIAUDIOCONNECTOR pInterface,
+                                                   PPDMAUDIOCALLBACK paCallbacks, size_t cCallbacks)
+{
+    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
+    AssertPtrReturn(paCallbacks, VERR_INVALID_POINTER);
+    AssertReturn(cCallbacks,     VERR_INVALID_PARAMETER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    for (size_t i = 0; i < cCallbacks; i++)
+    {
+        PPDMAUDIOCALLBACK pCB = drvAudioCallbackDuplicate(&paCallbacks[i]);
+        if (!pCB)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        switch (pCB->enmType)
+        {
+            case PDMAUDIOCALLBACKTYPE_INPUT:
+                RTListAppend(&pThis->lstCBIn, &pCB->Node);
+                break;
+
+            case PDMAUDIOCALLBACKTYPE_OUTPUT:
+                RTListAppend(&pThis->lstCBOut, &pCB->Node);
+                break;
+
+            default:
+                AssertMsgFailed(("Not supported\n"));
+                break;
+        }
+    }
+
+    /** @todo Undo allocations on error. */
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioCallback(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCALLBACKTYPE enmType,
+                                          void *pvUser, size_t cbUser)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvUser,     VERR_INVALID_POINTER);
+    AssertReturn(cbUser,        VERR_INVALID_PARAMETER);
+
+    PDRVAUDIO     pThis       = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+    PRTLISTANCHOR pListAnchor = NULL;
+
+    switch (enmType)
+    {
+        case PDMAUDIOCALLBACKTYPE_INPUT:
+            pListAnchor = &pThis->lstCBIn;
+            break;
+
+        case PDMAUDIOCALLBACKTYPE_OUTPUT:
+            pListAnchor = &pThis->lstCBOut;
+            break;
+
+        default:
+            AssertMsgFailed(("Not supported\n"));
+            break;
+    }
+
+    if (pListAnchor)
+    {
+        PPDMAUDIOCALLBACK pCB;
+        RTListForEach(pListAnchor, pCB, PDMAUDIOCALLBACK, Node)
+        {
+            Assert(pCB->enmType == enmType);
+            pCB->pfnCallback(enmType, pCB->pvCtx, pCB->cbCtx, pvUser, cbUser);
+        }
+    }
+
+    return VINF_SUCCESS;
+}
+#endif
+
+/**
+ * Initializes the host backend and queries its initial configuration.
+ * If the host backend fails, VERR_AUDIO_BACKEND_INIT_FAILED will be returned.
+ *
+ * Note: As this routine is called when attaching to the device LUN in the
+ *       device emulation, we either check for success or VERR_AUDIO_BACKEND_INIT_FAILED.
+ *       Everything else is considered as fatal and must be handled separately in
+ *       the device emulation!
+ *
+ * @return  IPRT status code.
+ * @param   pThis               Driver instance to be called.
+ * @param   pCfgHandle          CFGM configuration handle to use for this driver.
+ */
+static int drvAudioHostInit(PDRVAUDIO pThis, PCFGMNODE pCfgHandle)
+{
+    /* pCfgHandle is optional. */
+    NOREF(pCfgHandle);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    AssertPtr(pThis->pHostDrvAudio);
+    int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("Audio: Initialization of host backend failed with %Rrc\n", rc));
+        return VERR_AUDIO_BACKEND_INIT_FAILED;
+    }
+
+    /* Get the configuration data from backend. */
+    rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("Audio: Getting host backend configuration failed with %Rrc\n", rc));
+        return VERR_AUDIO_BACKEND_INIT_FAILED;
+    }
+
+    uint32_t cMaxHstStrmsOut = pThis->BackendCfg.cMaxHstStrmsOut;
+    size_t cbHstStrmsOut     = pThis->BackendCfg.cbStreamOut;
+
+    if (cbHstStrmsOut)
+    {
+        pThis->cFreeOutputStreams = cMaxHstStrmsOut;
+    }
+    else
+        pThis->cFreeOutputStreams = 0;
+
+    uint32_t cMaxHstStrmsIn = pThis->BackendCfg.cMaxHstStrmsIn;
+    size_t cbHstStrmIn      = pThis->BackendCfg.cbStreamIn;
+
+    if (cbHstStrmIn)
+    {
+        /*
+         * Note:
+         *  - Our AC'97 emulation has two inputs, line (ac97.pi) and microphone (ac97.mc).
+         *  - Our HDA emulation currently has only line input (hda.pi).
+         */
+        pThis->cFreeInputStreams = cMaxHstStrmsIn;
+    }
+    else
+        pThis->cFreeInputStreams = 0;
+
+    LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%zu), cMaxHstStrmsIn=%RU32 (cb=%zu)\n",
+                 cMaxHstStrmsOut, cbHstStrmsOut, cMaxHstStrmsIn, cbHstStrmIn));
+
+    LogFlowFunc(("cFreeInputStreams=%RU8, cFreeOutputStreams=%RU8\n",
+                 pThis->cFreeInputStreams, pThis->cFreeOutputStreams));
+
+    LogRel(("Audio: Host audio backend supports %RU32 output streams and %RU32 input streams at once\n",
+            /* Clamp for logging. Unlimited streams are defined by UINT32_MAX. */
+            RT_MIN(64, cMaxHstStrmsOut), RT_MIN(64, cMaxHstStrmsIn)));
+
+    LogFlowFuncLeave();
+    return VINF_SUCCESS;
+}
+
+static void drvAudioStateHandler(PPDMDRVINS pDrvIns, PDMAUDIOSTREAMCMD enmCmd)
+{
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+
+    LogFlowFunc(("enmCmd=%RU32\n", enmCmd));
+
+    if (!pThis->pHostDrvAudio)
+        return;
+
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
+        drvAudioControlHstOut(pThis, pHstStrmOut, enmCmd);
+
+    PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
+    while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
+        drvAudioControlHstIn(pThis, pHstStrmIn, enmCmd);
+}
+
+static struct audio_option audio_options[] =
+{
+    /* DAC */
+    {"DACFixedSettings", AUD_OPT_BOOL, &conf.fixed_out.enabled,
+     "Use fixed settings for host DAC", NULL, 0},
+
+    {"DACFixedFreq", AUD_OPT_INT, &conf.fixed_out.settings.uHz,
+     "Frequency for fixed host DAC", NULL, 0},
+
+    {"DACFixedFmt", AUD_OPT_FMT, &conf.fixed_out.settings.enmFormat,
+     "Format for fixed host DAC", NULL, 0},
+
+    {"DACFixedChannels", AUD_OPT_INT, &conf.fixed_out.settings.cChannels,
+     "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
+
+    {"DACVoices", AUD_OPT_INT, &conf.fixed_out.cStreams, /** @todo Rename! */
+     "Number of streams for DAC", NULL, 0},
+
+    /* ADC */
+    {"ADCFixedSettings", AUD_OPT_BOOL, &conf.fixed_in.enabled,
+     "Use fixed settings for host ADC", NULL, 0},
+
+    {"ADCFixedFreq", AUD_OPT_INT, &conf.fixed_in.settings.uHz,
+     "Frequency for fixed host ADC", NULL, 0},
+
+    {"ADCFixedFmt", AUD_OPT_FMT, &conf.fixed_in.settings.enmFormat,
+     "Format for fixed host ADC", NULL, 0},
+
+    {"ADCFixedChannels", AUD_OPT_INT, &conf.fixed_in.settings.cChannels,
+     "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
+
+    {"ADCVoices", AUD_OPT_INT, &conf.fixed_in.cStreams, /** @todo Rename! */
+     "Number of streams for ADC", NULL, 0},
+
+    /* Misc */
+    {"TimerFreq", AUD_OPT_INT, &conf.period.hz,
+     "Timer frequency in Hz (0 - use lowest possible)", NULL, 0},
+
+    {"PLIVE", AUD_OPT_BOOL, &conf.plive,
+     "(undocumented)", NULL, 0}, /** @todo What is this? */
+
+    {NULL, AUD_OPT_INT, NULL, NULL, NULL, 0}
+};
+
+static DECLCALLBACK(int) drvAudioInit(PCFGMNODE pCfgHandle, PPDMDRVINS pDrvIns)
+{
+    AssertPtrReturn(pCfgHandle, VERR_INVALID_POINTER);
+    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
+
+    LogRel(("Audio: Using VBox 5.0.x audio code!\n"));
+
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+    LogFlowFunc(("pDrvAudio=%p, pDrvIns=%p\n", pThis, pDrvIns));
+
+    RTListInit(&pThis->lstHstStrmIn);
+    RTListInit(&pThis->lstHstStrmOut);
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    RTListInit(&pThis->lstCBIn);
+    RTListInit(&pThis->lstCBOut);
+#endif
+
+    int rc = RTCritSectInit(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        rc = drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options);
+        /** @todo Check for invalid options? */
+
+        pThis->cFreeOutputStreams = conf.fixed_out.cStreams;
+        pThis->cFreeInputStreams  = conf.fixed_in.cStreams;
+
+        if (!pThis->cFreeOutputStreams)
+            pThis->cFreeOutputStreams = 1;
+
+        if (!pThis->cFreeInputStreams)
+            pThis->cFreeInputStreams = 1;
+    }
+
+    /*
+     * If everything went well, initialize the lower driver.
+     */
+    if (RT_SUCCESS(rc))
+        rc = drvAudioHostInit(pThis, pCfgHandle);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn,
+                                      void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+{
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    AssertPtrReturn(pGstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
+    AssertReturn(cbBuf,         VERR_INVALID_PARAMETER);
+    /* pcbWritten is optional. */
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_IN))
+    {
+        if (pcbRead)
+            *pcbRead = 0;
+
+        return RTCritSectLeave(&pThis->CritSect);
+    }
+
+    PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    AssertMsg(pGstStrmIn->pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
+              ("Reading from disabled host input stream \"%s\" not possible\n", pGstStrmIn->MixBuf.pszName));
+
+    /*
+     * Read from the parent buffer (that is, the guest buffer) which
+     * should have the audio data in the format the guest needs.
+     */
+    uint32_t cRead;
+    rc = AudioMixBufReadCirc(&pGstStrmIn->MixBuf, pvBuf, cbBuf, &cRead);
+    if (RT_SUCCESS(rc))
+    {
+        AudioMixBufFinish(&pGstStrmIn->MixBuf, cRead);
+
+        if (pcbRead)
+            *pcbRead = AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead);
+    }
+
+    LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
+                 cRead, AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead), rc));
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioEnableOut(PPDMIAUDIOCONNECTOR pInterface,
+                                           PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    /* pGstStrmOut is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = VINF_SUCCESS;
+
+    if (pGstStrmOut)
+    {
+        PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
+        AssertPtr(pHstStrmOut);
+
+        if (fEnable)
+        {
+            /* Is a pending disable outstanding? Then disable first. */
+            if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
+            {
+                rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+                if (RT_SUCCESS(rc))
+                    pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+            }
+
+            if (RT_SUCCESS(rc))
+                rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
+        }
+        else /* Disable */
+        {
+            if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+            {
+                uint32_t cGstStrmsActive = 0;
+
+                /*
+                 * Check if there are any active guest streams assigned
+                 * to this host stream which still are being marked as active.
+                 *
+                 * In that case we have to defer closing the host stream and
+                 * wait until all guest streams have been finished.
+                 */
+                PPDMAUDIOGSTSTRMOUT pIter;
+                RTListForEach(&pHstStrmOut->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
+                {
+                    if (pIter->State.fActive)
+                    {
+                        cGstStrmsActive++;
+                        break; /* At least one assigned & active guest stream is enough. */
+                    }
+                }
+
+                /* Do we need to defer closing the host stream? */
+                if (cGstStrmsActive >= 1)
+                    pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+
+                /* Can we close the host stream now instead of deferring it? */
+                if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE))
+                    rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+            }
+        }
+
+        if (RT_SUCCESS(rc))
+            pGstStrmOut->State.fActive = fEnable;
+
+        LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",
+                     pGstStrmOut->MixBuf.pszName, fEnable, pHstStrmOut->fStatus, rc));
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioEnableIn(PPDMIAUDIOCONNECTOR pInterface,
+                                          PPDMAUDIOGSTSTRMIN pGstStrmIn, bool fEnable)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    /* pGstStrmIn is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = VINF_SUCCESS;
+
+    if (pGstStrmIn)
+    {
+        PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
+        AssertPtr(pHstStrmIn);
+
+        LogFlowFunc(("%s: fEnable=%RTbool\n", pGstStrmIn->MixBuf.pszName, fEnable));
+
+        rc = drvAudioControlHstIn(pThis, pHstStrmIn,
+                                  fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
+        if (RT_SUCCESS(rc))
+            pGstStrmIn->State.fActive = fEnable;
+
+        LogFlowFunc(("%s: fEnable=%RTbool, rc=%Rrc\n", pGstStrmIn->MixBuf.pszName, fEnable, rc));
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvAudioIsValidIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN  pGstStrmIn)
+{
+    RT_NOREF(pInterface);
+    return (pGstStrmIn != NULL);
+}
+
+static DECLCALLBACK(bool) drvAudioIsValidOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+    RT_NOREF(pInterface);
+    return (pGstStrmOut != NULL);
+}
+
+static DECLCALLBACK(int) drvAudioCreateIn(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+                                          PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
+                                          PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
+{
+    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
+    AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,        VERR_INVALID_POINTER);
+    AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    LogFlowFunc(("pszName=%s, pCfg=%p\n", pszName, pCfg));
+
+    if (!drvAudioStreamCfgIsValid(pCfg))
+    {
+        LogFunc(("Input stream configuration is not valid, bailing out\n"));
+        rc = VERR_INVALID_PARAMETER;
+    }
+
+    PPDMAUDIOGSTSTRMIN pGstStrmIn = *ppGstStrmIn;
+    if (   RT_SUCCESS(rc)
+        && pGstStrmIn
+        && drvAudioPCMPropsAreEqual(&pGstStrmIn->Props, pCfg))
+    {
+        LogFunc(("[%s] Exists and matches required configuration, skipping creation\n",
+                 pGstStrmIn->MixBuf.pszName));
+        rc = VWRN_ALREADY_EXISTS;
+    }
+
+    if (rc != VINF_SUCCESS) /* Note: Can be VWRN_ALREADY_EXISTS, so don't use VINF_SUCCESS here. */
+    {
+        int rc2 = RTCritSectLeave(&pThis->CritSect);
+        AssertRC(rc2);
+
+        return rc;
+    }
+
+    if (   !conf.fixed_in.enabled
+        && pGstStrmIn)
+    {
+        drvAudioDestroyGstIn(pThis, pGstStrmIn);
+        pGstStrmIn = NULL;
+    }
+
+    if (pGstStrmIn)
+    {
+        PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
+        AssertPtr(pHstStrmIn);
+
+        drvAudioGstInFreeRes(pGstStrmIn);
+
+        char *pszTemp;
+        if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
+        {
+            RTMemFree(pGstStrmIn);
+
+            int rc2 = RTCritSectLeave(&pThis->CritSect);
+            AssertRC(rc2);
+
+            return VERR_NO_MEMORY;
+        }
+
+        rc = drvAudioGstInInit(pGstStrmIn, pHstStrmIn, pszName, pCfg);
+
+        RTStrFree(pszTemp);
+    }
+    else
+        rc = drvAudioCreateStreamPairIn(pThis, pszName, enmRecSource, pCfg, &pGstStrmIn);
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pGstStrmIn)
+            *ppGstStrmIn = pGstStrmIn;
+    }
+    else
+    {
+        switch (rc)
+        {
+            case VERR_NO_MORE_HANDLES: /** @todo Find a better rc. */
+                LogRel(("Audio: Skipping to create input stream \"%s\", " \
+                        "as the host audio backend reached its maximum of concurrent audio input streams\n", pszName));
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioCreateOut(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+                                           PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
+{
+    AssertPtrReturn(pInterface,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pszName,      VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,         VERR_INVALID_POINTER);
+    AssertPtrReturn(ppGstStrmOut, VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    LogFlowFunc(("pszName=%s, pCfg=%p\n", pszName, pCfg));
+
+    if (!drvAudioStreamCfgIsValid(pCfg))
+    {
+        LogFunc(("Output stream configuration is not valid, bailing out\n"));
+        rc = VERR_INVALID_PARAMETER;
+    }
+
+    PPDMAUDIOGSTSTRMOUT pGstStrmOut = *ppGstStrmOut;
+    if (   RT_SUCCESS(rc)
+        && pGstStrmOut
+        && drvAudioPCMPropsAreEqual(&pGstStrmOut->Props, pCfg))
+    {
+        LogFunc(("[%s] Exists and matches required configuration, skipping creation\n",
+                 pGstStrmOut->MixBuf.pszName));
+
+        rc = VWRN_ALREADY_EXISTS;
+    }
+
+    if (rc != VINF_SUCCESS) /* Note: Can be VWRN_ALREADY_EXISTS, so don't use VINF_SUCCESS here. */
+    {
+        int rc2 = RTCritSectLeave(&pThis->CritSect);
+        AssertRC(rc2);
+
+        return rc;
+    }
+
+#if 0
+    /* Any live samples that need to be updated after
+     * we set the new parameters? */
+    PPDMAUDIOGSTSTRMOUT pOldGstStrmOut = NULL;
+    uint32_t cLiveSamples = 0;
+
+    if (   conf.plive
+        && pGstStrmOut
+        && (   !pGstStrmOut->State.fActive
+            && !pGstStrmOut->State.fEmpty))
+    {
+        cLiveSamples = pGstStrmOut->cTotalSamplesWritten;
+        if (cLiveSamples)
+        {
+            pOldGstStrmOut = pGstStrmOut;
+            pGstStrmOut = NULL;
+        }
+    }
+#endif
+
+    if (   pGstStrmOut
+        && !conf.fixed_out.enabled)
+    {
+        drvAudioDestroyGstOut(pThis, pGstStrmOut);
+        pGstStrmOut = NULL;
+    }
+
+    if (pGstStrmOut)
+    {
+        PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
+        AssertPtr(pHstStrmOut);
+
+        drvAudioGstOutFreeRes(pGstStrmOut);
+
+        rc = drvAudioGstOutInit(pGstStrmOut, pHstStrmOut, pszName, pCfg);
+    }
+    else
+    {
+        rc = drvAudioCreateStreamPairOut(pThis, pszName, pCfg, &pGstStrmOut);
+        if (RT_FAILURE(rc))
+            LogFunc(("Failed to create output stream \"%s\", rc=%Rrc\n", pszName, rc));
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pGstStrmOut)
+            *ppGstStrmOut = pGstStrmOut;
+#if 0
+        /* Update remaining live samples with new rate. */
+        if (cLiveSamples)
+        {
+            AssertPtr(pOldGstStrmOut);
+
+            uint32_t cSamplesMixed =
+                (cLiveSamples << pOldGstStrmOut->Props.cShift)
+                * pOldGstStrmOut->Props.cbPerSec
+                / (*ppGstStrmOut)->Props.cbPerSec;
+
+            pGstStrmOut->cTotalSamplesWritten += cSamplesMixed;
+        }
+#endif
+    }
+    else
+    {
+        switch (rc)
+        {
+            case VERR_NO_MORE_HANDLES: /** @todo Find a better rc. */
+                LogRel(("Audio: Skipping to create output stream \"%s\", " \
+                        "as the host audio backend reached its maximum of concurrent audio output streams\n", pszName));
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioGetConfiguration(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, pCfg);
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvAudioIsActiveIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
+{
+    AssertPtrReturn(pInterface, false);
+    /* pGstStrmIn is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    bool fRet = pGstStrmIn ? pGstStrmIn->State.fActive : false;
+
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+
+    return fRet;
+}
+
+static DECLCALLBACK(bool) drvAudioIsActiveOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+    AssertPtrReturn(pInterface,  false);
+    /* pGstStrmOut is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    bool fRet = pGstStrmOut ? pGstStrmOut->State.fActive : false;
+
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+
+    return fRet;
+}
+
+static DECLCALLBACK(void) drvAudioDestroyIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
+{
+    AssertPtrReturnVoid(pInterface);
+    /* pGstStrmIn is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    if (pGstStrmIn)
+        drvAudioDestroyGstIn(pThis, pGstStrmIn);
+
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+}
+
+static DECLCALLBACK(void) drvAudioDestroyOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+    AssertPtrReturnVoid(pInterface);
+    /* pGstStrmOut is optional. */
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    if (pGstStrmOut)
+        drvAudioDestroyGstOut(pThis, pGstStrmOut);
+
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+}
+
+/********************************************************************/
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));
+
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
+
+    return NULL;
+}
+
+/**
+ * Power Off notification.
+ *
+ * @param   pDrvIns     The driver instance data.
+ */
+static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
+{
+    LogFlowFuncEnter();
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+
+    if (!pThis->pHostDrvAudio)
+        return;
+
+    /* Tear down all host output streams. */
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+    while ((pHstStrmOut = drvAudioFindAnyHstOut(pThis, pHstStrmOut)))
+    {
+        drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+        pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
+    }
+
+    /* Tear down all host input streams. */
+    PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
+    while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
+    {
+        drvAudioControlHstIn(pThis, pHstStrmIn, PDMAUDIOSTREAMCMD_DISABLE);
+        pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, pHstStrmIn);
+    }
+
+    if (pThis->pHostDrvAudio->pfnShutdown)
+        pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    PPDMAUDIOCALLBACK pCB, pCBNext;
+    RTListForEachSafe(&pThis->lstCBIn, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
+        drvAudioCallbackDestroy(pCB);
+
+    RTListForEachSafe(&pThis->lstCBOut, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
+        drvAudioCallbackDestroy(pCB);
+#endif
+
+    LogFlowFuncLeave();
+}
+
+/**
+ * Constructs an audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
+{
+    LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));
+
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                                   = pDrvIns;
+    /* IBase. */
+    pDrvIns->IBase.pfnQueryInterface                 = drvAudioQueryInterface;
+    /* IAudioConnector. */
+    pThis->IAudioConnector.pfnQueryStatus            = drvAudioQueryStatus;
+    pThis->IAudioConnector.pfnRead                   = drvAudioRead;
+    pThis->IAudioConnector.pfnWrite                  = drvAudioWrite;
+    pThis->IAudioConnector.pfnGetConfiguration       = drvAudioGetConfiguration;
+    pThis->IAudioConnector.pfnIsActiveIn             = drvAudioIsActiveIn;
+    pThis->IAudioConnector.pfnIsActiveOut            = drvAudioIsActiveOut;
+    pThis->IAudioConnector.pfnIsValidIn              = drvAudioIsValidIn;
+    pThis->IAudioConnector.pfnIsValidOut             = drvAudioIsValidOut;
+    pThis->IAudioConnector.pfnEnableOut              = drvAudioEnableOut;
+    pThis->IAudioConnector.pfnEnableIn               = drvAudioEnableIn;
+    pThis->IAudioConnector.pfnDestroyIn              = drvAudioDestroyIn;
+    pThis->IAudioConnector.pfnDestroyOut             = drvAudioDestroyOut;
+    pThis->IAudioConnector.pfnCreateIn               = drvAudioCreateIn;
+    pThis->IAudioConnector.pfnCreateOut              = drvAudioCreateOut;
+    pThis->IAudioConnector.pfnPlayOut                = drvAudioPlayOut;
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    pThis->IAudioConnector.pfnRegisterCallbacks      = drvAudioRegisterCallbacks;
+    pThis->IAudioConnector.pfnCallback               = drvAudioCallback;
+#endif
+
+    /*
+     * Attach driver below and query its connector interface.
+     */
+    PPDMIBASE pDownBase;
+    int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pDownBase);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("Audio: Failed to attach to driver %p below (flags=0x%x), rc=%Rrc\n",
+                pDrvIns, fFlags, rc));
+        return rc;
+    }
+
+    pThis->pHostDrvAudio = PDMIBASE_QUERY_INTERFACE(pDownBase, PDMIHOSTAUDIO);
+    if (!pThis->pHostDrvAudio)
+    {
+        LogRel(("Audio: Failed to query interface for underlying host driver\n"));
+        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
+                                N_("Host audio backend missing or invalid"));
+    }
+
+#ifdef DEBUG_andy
+    CFGMR3Dump(pCfgHandle);
+#endif
+
+    rc = drvAudioInit(pCfgHandle, pDrvIns);
+    if (RT_SUCCESS(rc))
+    {
+        pThis->fTerminate = false;
+        pThis->pDrvIns    = pDrvIns;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Destructs an audio driver instance.
+ *
+ * @copydoc FNPDMDRVDESTRUCT
+ */
+static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
+{
+    LogFlowFuncEnter();
+
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+
+    if (RTCritSectIsInitialized(&pThis->CritSect))
+    {
+        int rc2 = RTCritSectDelete(&pThis->CritSect);
+        AssertRC(rc2);
+    }
+}
+
+/**
+ * Suspend notification.
+ *
+ * @param   pDrvIns     The driver instance data.
+ */
+static DECLCALLBACK(void) drvAudioSuspend(PPDMDRVINS pDrvIns)
+{
+    drvAudioStateHandler(pDrvIns, PDMAUDIOSTREAMCMD_PAUSE);
+}
+
+/**
+ * Resume notification.
+ *
+ * @param   pDrvIns     The driver instance data.
+ */
+static DECLCALLBACK(void) drvAudioResume(PPDMDRVINS pDrvIns)
+{
+    drvAudioStateHandler(pDrvIns, PDMAUDIOSTREAMCMD_RESUME);
+}
+
+/**
+ * Audio driver registration record.
+ */
+const PDMDRVREG g_DrvAUDIO =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "AUDIO",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Audio connector driver",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    2,
+    /* cbInstance */
+    sizeof(DRVAUDIO),
+    /* pfnConstruct */
+    drvAudioConstruct,
+    /* pfnDestruct */
+    drvAudioDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    drvAudioSuspend,
+    /* pfnResume */
+    drvAudioResume,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    drvAudioPowerOff,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
diff --git a/src/VBox/Devices/Audio_50/DrvAudio.h b/src/VBox/Devices/Audio_50/DrvAudio.h
new file mode 100644
index 0000000..e48c62a
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvAudio.h
@@ -0,0 +1,156 @@
+/* $Id: DrvAudio.h $ */
+/** @file
+ * Intermediate audio driver header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: audio.h
+ *
+ * QEMU Audio subsystem header
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef DRV_AUDIO_H
+#define DRV_AUDIO_H
+
+#include <limits.h>
+
+#include <iprt/circbuf.h>
+#include <iprt/critsect.h>
+
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdm.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+typedef enum
+{
+    AUD_OPT_INT,
+    AUD_OPT_FMT,
+    AUD_OPT_STR,
+    AUD_OPT_BOOL
+} audio_option_tag_e;
+
+typedef struct audio_option
+{
+    const char *name;
+    audio_option_tag_e tag;
+    void *valp;
+    const char *descr;
+    int *overridenp;
+    int overriden;
+} audio_option;
+
+/**
+ * Audio driver instance data.
+ *
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVAUDIO
+{
+    /** Input/output processing thread. */
+    RTTHREAD                hThread;
+    /** Critical section for serializing access. */
+    RTCRITSECT              CritSect;
+    /** Shutdown indicator. */
+    bool                    fTerminate;
+    /** Our audio connector interface. */
+    PDMIAUDIOCONNECTOR      IAudioConnector;
+    /** Pointer to the driver instance. */
+    PPDMDRVINS              pDrvIns;
+    /** Pointer to audio driver below us. */
+    PPDMIHOSTAUDIO          pHostDrvAudio;
+    /** List of host input streams. */
+    RTLISTANCHOR            lstHstStrmIn;
+    /** List of host output streams. */
+    RTLISTANCHOR            lstHstStrmOut;
+    /** Max. number of free input streams.
+     *  UINT32_MAX for unlimited streams. */
+    uint32_t                cFreeInputStreams;
+    /** Max. number of free output streams.
+     *  UINT32_MAX for unlimited streams. */
+    uint32_t                cFreeOutputStreams;
+    /** Audio configuration settings retrieved from the backend. */
+    PDMAUDIOBACKENDCFG      BackendCfg;
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    /** @todo Use a map with primary key set to the callback type? */
+    RTLISTANCHOR            lstCBIn;
+    RTLISTANCHOR            lstCBOut;
+#endif
+} DRVAUDIO, *PDRVAUDIO;
+
+/** Makes a PDRVAUDIO out of a PPDMIAUDIOCONNECTOR. */
+#define PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface) \
+    ( (PDRVAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVAUDIO, IAudioConnector)) )
+
+const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat);
+const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource);
+PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat);
+
+bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS info, PPDMAUDIOSTREAMCFG pCfg);
+void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg);
+
+/* AUDIO IN function declarations. */
+void drvAudioHlpPcmSwFreeResourcesIn(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+void drvAudioGstInRemove(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+void drvAudioGstInRemove(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+int  drvAudioGstInInit(PPDMAUDIOGSTSTRMIN pGstStrmIn, PPDMAUDIOHSTSTRMIN pHstStrmIn, const char *pszName, PPDMAUDIOSTREAMCFG pCfg);
+
+PPDMAUDIOHSTSTRMIN drvAudioFindNextHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEnabledHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEqHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg);
+
+/* AUDIO OUT function declarations. */
+int  drvAudioGstOutAlloc(PPDMAUDIOGSTSTRMOUT pGstStrmOut);
+void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut);
+void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+int  drvAudioDestroyGstOut(PDRVAUDIO pDrvAudio, PPDMAUDIOGSTSTRMOUT pGstStrmOut);
+void drvAudioDestroyHstOut(PDRVAUDIO pDrvAudio, PDMAUDIOHSTSTRMOUT pHstStrmOut);
+int  drvAudioGstOutInit(PPDMAUDIOGSTSTRMOUT pGstStrmOut, PPDMAUDIOHSTSTRMOUT pHstStrmOut, const char *pszName, PPDMAUDIOSTREAMCFG pCfg);
+
+PPDMAUDIOHSTSTRMOUT drvAudioFindAnyHstOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+PPDMAUDIOHSTSTRMOUT drvAudioHstFindAnyEnabledOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+PPDMAUDIOHSTSTRMOUT drvAudioFindSpecificOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg);
+int drvAudioAllocHstOut(PDRVAUDIO pDrvAudio, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut);
+int drvAudioHlpPcmHwAddOut(PDRVAUDIO pDrvAudio, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut);
+int drvAudioHlpPcmCreateVoicePairOut(PDRVAUDIO pDrvAudio, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut);
+
+/* Common functions between DrvAudio and backends (host audio drivers). */
+void DrvAudioClearBuf(PPDMPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
+int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps);
+
+#endif /* DRV_AUDIO_H */
diff --git a/src/VBox/Devices/Audio_50/DrvAudioCommon.cpp b/src/VBox/Devices/Audio_50/DrvAudioCommon.cpp
new file mode 100644
index 0000000..12c1e2c
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvAudioCommon.cpp
@@ -0,0 +1,413 @@
+/* $Id: DrvAudioCommon.cpp $ */
+/** @file
+ * Intermedia audio driver, common routines. These are also used
+ * in the drivers which are bound to Main, e.g. the VRDE or the
+ * video audio recording drivers.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: audio_template.h from QEMU AUDIO subsystem.
+ *
+ * QEMU Audio subsystem header
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define LOG_GROUP LOG_GROUP_DRV_AUDIO
+#include <VBox/log.h>
+#include <iprt/asm-math.h>
+#include <iprt/assert.h>
+#include <iprt/uuid.h>
+#include <iprt/string.h>
+#include <iprt/alloc.h>
+
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdm.h>
+#include <VBox/err.h>
+#include <VBox/vmm/mm.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg);
+
+const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource)
+{
+    switch (enmRecSource)
+    {
+        case PDMAUDIORECSOURCE_MIC:     return "Microphone In";
+        case PDMAUDIORECSOURCE_CD:      return "CD";
+        case PDMAUDIORECSOURCE_VIDEO:   return "Video";
+        case PDMAUDIORECSOURCE_AUX:     return "AUX";
+        case PDMAUDIORECSOURCE_LINE_IN: return "Line In";
+        case PDMAUDIORECSOURCE_PHONE:   return "Phone";
+        default:
+            break;
+    }
+
+    AssertMsgFailed(("Bogus recording source %ld\n", enmRecSource));
+    return "Unknown";
+}
+
+const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat)
+{
+    switch (enmFormat)
+    {
+        case AUD_FMT_U8:
+            return "U8";
+
+        case AUD_FMT_U16:
+            return "U16";
+
+        case AUD_FMT_U32:
+            return "U32";
+
+        case AUD_FMT_S8:
+            return "S8";
+
+        case AUD_FMT_S16:
+            return "S16";
+
+        case AUD_FMT_S32:
+            return "S32";
+
+        default:
+            break;
+    }
+
+    AssertMsgFailed(("Bogus audio format %ld\n", enmFormat));
+    return "Invalid";
+}
+
+PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat)
+{
+    if (!RTStrICmp(pszFormat, "u8"))
+        return AUD_FMT_U8;
+    else if (!RTStrICmp(pszFormat, "u16"))
+        return AUD_FMT_U16;
+    else if (!RTStrICmp(pszFormat, "u32"))
+        return AUD_FMT_U32;
+    else if (!RTStrICmp(pszFormat, "s8"))
+        return AUD_FMT_S8;
+    else if (!RTStrICmp(pszFormat, "s16"))
+        return AUD_FMT_S16;
+    else if (!RTStrICmp(pszFormat, "s32"))
+        return AUD_FMT_S32;
+
+    AssertMsgFailed(("Bogus audio format \"%s\"\n", pszFormat));
+    return AUD_FMT_INVALID;
+}
+
+/*********************************** In Stream Functions **********************************************/
+
+void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
+{
+    AssertPtrReturnVoid(pGstStrmIn);
+
+    if (pGstStrmIn->State.pszName)
+    {
+        RTStrFree(pGstStrmIn->State.pszName);
+        pGstStrmIn->State.pszName = NULL;
+    }
+
+    AudioMixBufDestroy(&pGstStrmIn->MixBuf);
+}
+
+void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    AssertPtrReturnVoid(pHstStrmIn);
+    AudioMixBufDestroy(&pHstStrmIn->MixBuf);
+}
+
+void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+    if (!pGstStrmOut)
+        return;
+
+    if (pGstStrmOut->State.pszName)
+    {
+        RTStrFree(pGstStrmOut->State.pszName);
+        pGstStrmOut->State.pszName = NULL;
+    }
+
+    AudioMixBufDestroy(&pGstStrmOut->MixBuf);
+}
+
+#if 0
+
+/**
+ * Finds the minimum number of not yet captured samples of all
+ * attached guest input streams for a certain host input stream.
+ *
+ * @return  uint32_t            Minimum number of not yet captured samples.
+ *                              UINT32_MAX if none found.
+ * @param   pHstStrmIn          Host input stream to check for.
+ */
+inline uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    AssertPtrReturn(pHstStrmIn, 0);
+    uint32_t cMinSamples = UINT32_MAX;
+
+    PPDMAUDIOGSTSTRMIN pGstStrmIn;
+    RTListForEach(&pHstStrmIn->lstGstStrmIn, pGstStrmIn, PDMAUDIOGSTSTRMIN, Node)
+    {
+        if (pGstStrmIn->State.fActive)
+            cMinSamples = RT_MIN(cMinSamples, audioMixBufMixed(&pGstStrmIn->MixBuf));
+    }
+
+#ifdef DEBUG_andy
+    LogFlowFunc(("cMinSamples=%RU32\n", cMinSamples));
+#endif
+    return cMinSamples;
+}
+
+uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    AssertPtrReturn(pHstStrmIn, 0);
+
+    return audioMixBufSize(&pHstStrmIn->MixBuf) - drvAudioHstInGetLive(pHstStrmIn);
+}
+
+uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    AssertPtrReturn(pHstStrmIn, 0);
+
+    uint32_t cMinSamplesCaptured = drvAudioHstInFindMinCaptured(pHstStrmIn);
+    uint32_t cSamplesCaptured = audioMixBufMixed(&pHstStrmIn->MixBuf);
+
+    Assert(cSamplesCaptured >= cMinSamplesCaptured);
+    uint32_t cSamplesLive = cSamplesCaptured - cMinSamplesCaptured;
+    Assert(cSamplesLive <= audioMixBufSize(&pHstStrmIn->MixBuf));
+
+#ifdef DEBUG_andy
+    LogFlowFunc(("cSamplesLive=%RU32\n", cSamplesLive));
+#endif
+    return cSamplesLive;
+}
+#endif
+
+void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    AssertPtrReturnVoid(pHstStrmOut);
+    AudioMixBufDestroy(&pHstStrmOut->MixBuf);
+}
+
+#if 0
+/**
+ * Returns the number of live sample data (in bytes) of a certain
+ * guest input stream.
+ *
+ * @return  uint32_t            Live sample data (in bytes), 0 if none.
+ * @param   pGstStrmIn          Guest input stream to check for.
+ */
+uint32_t drvAudioGstInGetLiveBytes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
+{
+    AssertPtrReturn(pGstStrmIn, 0);
+    AssertPtrReturn(pGstStrmIn->pHstStrmIn, 0);
+
+    Assert(pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured >= pGstStrmIn->cTotalHostSamplesRead);
+    uint32_t cSamplesLive = pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured - pGstStrmIn->cTotalHostSamplesRead;
+    if (!cSamplesLive)
+        return 0;
+    Assert(cSamplesLive <= pGstStrmIn->pHstStrmIn->cSamples);
+
+    /** @todo Document / refactor this! */
+    return (((int64_t) cSamplesLive << 32) / pGstStrmIn->State.uFreqRatio) << pGstStrmIn->Props.cShift;
+}
+
+
+/**
+ * Returns the total number of unused sample data (in bytes) of a certain
+ * guest output stream.
+ *
+ * @return  uint32_t            Number of unused sample data (in bytes), 0 if all used up.
+ * @param   pGstStrmOut         Guest output stream to check for.
+ */
+uint32_t drvAudioGstOutGetFreeBytes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+    AssertPtrReturn(pGstStrmOut, 0);
+
+    Assert(pGstStrmOut->cTotalSamplesWritten <= pGstStrmOut->pHstStrmOut->cSamples);
+    uint32_t cSamplesFree =   pGstStrmOut->pHstStrmOut->cSamples
+                            - pGstStrmOut->cTotalSamplesWritten;
+    if (!cSamplesFree)
+        return 0;
+
+    /** @todo Document / refactor this! */
+    return (((int64_t) cSamplesFree << 32) / pGstStrmOut->State.uFreqRatio) << pGstStrmOut->Props.cShift;
+}
+#endif
+
+bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
+{
+    int cBits = 8;
+    bool fSigned = false;
+
+    switch (pCfg->enmFormat)
+    {
+        case AUD_FMT_S8:
+            fSigned = true;
+        case AUD_FMT_U8:
+            break;
+
+        case AUD_FMT_S16:
+            fSigned = true;
+        case AUD_FMT_U16:
+            cBits = 16;
+            break;
+
+        case AUD_FMT_S32:
+            fSigned = true;
+        case AUD_FMT_U32:
+            cBits = 32;
+            break;
+
+        default:
+            AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
+            break;
+    }
+
+    bool fEqual =    pProps->uHz         == pCfg->uHz
+                  && pProps->cChannels   == pCfg->cChannels
+                  && pProps->fSigned     == fSigned
+                  && pProps->cBits       == cBits
+                  && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
+
+    LogFlowFunc(("fEqual=%RTbool\n", fEqual));
+    return fEqual;
+}
+
+/**
+ * Converts an audio stream configuration to matching PCM properties.
+ *
+ * @return  IPRT status code.
+ * @param   pCfg                    Audio stream configuration to convert.
+ * @param   pProps                  PCM properties to save result to.
+ */
+int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
+{
+    AssertPtrReturn(pCfg,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pProps, VERR_INVALID_POINTER);
+
+    int rc = VINF_SUCCESS;
+
+    int cBits = 8, cShift = 0;
+    bool fSigned = false;
+
+    switch (pCfg->enmFormat)
+    {
+        case AUD_FMT_S8:
+            fSigned = true;
+        case AUD_FMT_U8:
+            break;
+
+        case AUD_FMT_S16:
+            fSigned = true;
+        case AUD_FMT_U16:
+            cBits = 16;
+            cShift = 1;
+            break;
+
+        case AUD_FMT_S32:
+            fSigned = true;
+        case AUD_FMT_U32:
+            cBits = 32;
+            cShift = 2;
+            break;
+
+        default:
+            AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        pProps->uHz         = pCfg->uHz;
+        pProps->cBits       = cBits;
+        pProps->fSigned     = fSigned;
+        pProps->cChannels   = pCfg->cChannels;
+        pProps->cShift      = (pCfg->cChannels == 2) + cShift;
+        pProps->uAlign      = (1 << pProps->cShift) - 1;
+        pProps->cbPerSec    = pProps->uHz << pProps->cShift;
+        pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
+    }
+
+    return rc;
+}
+
+void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
+{
+    LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=",
+                 pCfg->uHz, pCfg->cChannels));
+
+    switch (pCfg->enmFormat)
+    {
+        case AUD_FMT_S8:
+            LogFlow(("S8"));
+            break;
+        case AUD_FMT_U8:
+            LogFlow(("U8"));
+            break;
+        case AUD_FMT_S16:
+            LogFlow(("S16"));
+            break;
+        case AUD_FMT_U16:
+            LogFlow(("U16"));
+            break;
+        case AUD_FMT_S32:
+            LogFlow(("S32"));
+            break;
+        case AUD_FMT_U32:
+            LogFlow(("U32"));
+            break;
+        default:
+            LogFlow(("invalid(%d)", pCfg->enmFormat));
+            break;
+    }
+
+    LogFlow((", endianness="));
+    switch (pCfg->enmEndianness)
+    {
+        case PDMAUDIOENDIANNESS_LITTLE:
+            LogFlow(("little\n"));
+            break;
+        case PDMAUDIOENDIANNESS_BIG:
+            LogFlow(("big\n"));
+            break;
+        default:
+            LogFlow(("invalid\n"));
+            break;
+    }
+}
diff --git a/src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp
new file mode 100644
index 0000000..23b4c3a
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp
@@ -0,0 +1,1425 @@
+/* $Id: DrvHostALSAAudio.cpp $ */
+/** @file
+ * VBox audio devices: ALSA audio driver.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: alsaaudio.c
+ *
+ * QEMU ALSA audio driver
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+#include <iprt/alloc.h>
+#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
+#include <VBox/vmm/pdmaudioifs.h>
+
+RT_C_DECLS_BEGIN
+ #include "alsa_stubs.h"
+ #include "alsa_mangling.h"
+RT_C_DECLS_END
+
+#include <alsa/asoundlib.h>
+
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+#include "VBoxDD.h"
+
+typedef struct ALSAAUDIOSTREAMIN
+{
+    PDMAUDIOHSTSTRMIN   pStreamIn;
+    snd_pcm_t          *phPCM;
+    void               *pvBuf;
+    size_t              cbBuf;
+} ALSAAUDIOSTREAMIN, *PALSAAUDIOSTREAMIN;
+
+typedef struct ALSAAUDIOSTREAMOUT
+{
+    PDMAUDIOHSTSTRMOUT  pStreamOut;
+    snd_pcm_t          *phPCM;
+    void               *pvBuf;
+    size_t              cbBuf;
+} ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT;
+
+/* latency = period_size * periods / (rate * bytes_per_frame) */
+
+typedef struct ALSAAUDIOCFG
+{
+    int size_in_usec_in;
+    int size_in_usec_out;
+    const char *pcm_name_in;
+    const char *pcm_name_out;
+    unsigned int buffer_size_in;
+    unsigned int period_size_in;
+    unsigned int buffer_size_out;
+    unsigned int period_size_out;
+    unsigned int threshold;
+
+    int buffer_size_in_overriden;
+    int period_size_in_overriden;
+
+    int buffer_size_out_overriden;
+    int period_size_out_overriden;
+
+} ALSAAUDIOCFG, *PALSAAUDIOCFG;
+
+static int drvHostALSAAudioRecover(snd_pcm_t *phPCM);
+
+static ALSAAUDIOCFG s_ALSAConf =
+{
+#ifdef HIGH_LATENCY
+    1,
+    1,
+#else
+    0,
+    0,
+#endif
+    "default",
+    "default",
+#ifdef HIGH_LATENCY
+    400000,
+    400000 / 4,
+    400000,
+    400000 / 4,
+#else
+# define DEFAULT_BUFFER_SIZE 1024
+# define DEFAULT_PERIOD_SIZE 256
+    DEFAULT_BUFFER_SIZE * 4,
+    DEFAULT_PERIOD_SIZE * 4,
+    DEFAULT_BUFFER_SIZE,
+    DEFAULT_PERIOD_SIZE,
+#endif
+    0,
+    0,
+    0,
+    0,
+    0
+};
+
+/**
+ * Host Alsa audio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTALSAAUDIO
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS         pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO      IHostAudio;
+    /** Error count for not flooding the release log.
+     *  UINT32_MAX for unlimited logging. */
+    uint32_t           cLogErrors;
+} DRVHOSTALSAAUDIO, *PDRVHOSTALSAAUDIO;
+
+/** Maximum number of tries to recover a broken pipe. */
+#define ALSA_RECOVERY_TRIES_MAX    5
+
+typedef struct ALSAAUDIOSTREAMCFG
+{
+    unsigned int freq;
+    snd_pcm_format_t fmt;
+    int nchannels;
+    unsigned long buffer_size;
+    unsigned long period_size;
+    snd_pcm_uframes_t samples;
+} ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG;
+
+static int drvHostALSAAudioClose(snd_pcm_t **pphPCM)
+{
+    if (!pphPCM || !*pphPCM)
+        return VINF_SUCCESS;
+
+    int rc;
+    int rc2 = snd_pcm_close(*pphPCM);
+    if (rc2)
+    {
+        LogRel(("ALSA: Closing PCM descriptor failed: %s\n", snd_strerror(rc2)));
+        rc = VERR_GENERAL_FAILURE; /** @todo */
+    }
+    else
+    {
+        *pphPCM = NULL;
+        rc = VINF_SUCCESS;
+    }
+
+    return rc;
+}
+
+static snd_pcm_format_t drvHostALSAAudioFmtToALSA(PDMAUDIOFMT fmt)
+{
+    switch (fmt)
+    {
+        case AUD_FMT_S8:
+            return SND_PCM_FORMAT_S8;
+
+        case AUD_FMT_U8:
+            return SND_PCM_FORMAT_U8;
+
+        case AUD_FMT_S16:
+            return SND_PCM_FORMAT_S16_LE;
+
+        case AUD_FMT_U16:
+            return SND_PCM_FORMAT_U16_LE;
+
+        case AUD_FMT_S32:
+            return SND_PCM_FORMAT_S32_LE;
+
+        case AUD_FMT_U32:
+            return SND_PCM_FORMAT_U32_LE;
+
+        default:
+            break;
+    }
+
+    AssertMsgFailed(("Format %ld not supported\n", fmt));
+    return SND_PCM_FORMAT_U8;
+}
+
+static int drvHostALSAAudioALSAToFmt(snd_pcm_format_t fmt,
+                                     PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
+{
+    AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
+    /* pEndianness is optional. */
+
+    switch (fmt)
+    {
+        case SND_PCM_FORMAT_S8:
+            *pFmt = AUD_FMT_S8;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case SND_PCM_FORMAT_U8:
+            *pFmt = AUD_FMT_U8;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case SND_PCM_FORMAT_S16_LE:
+            *pFmt = AUD_FMT_S16;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case SND_PCM_FORMAT_U16_LE:
+            *pFmt = AUD_FMT_U16;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case SND_PCM_FORMAT_S16_BE:
+            *pFmt = AUD_FMT_S16;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+        case SND_PCM_FORMAT_U16_BE:
+            *pFmt = AUD_FMT_U16;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+        case SND_PCM_FORMAT_S32_LE:
+            *pFmt = AUD_FMT_S32;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case SND_PCM_FORMAT_U32_LE:
+            *pFmt = AUD_FMT_U32;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case SND_PCM_FORMAT_S32_BE:
+            *pFmt = AUD_FMT_S32;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+        case SND_PCM_FORMAT_U32_BE:
+            *pFmt = AUD_FMT_U32;
+            if (pEndianness)
+                *pEndianness = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+        default:
+            AssertMsgFailed(("Format %ld not supported\n", fmt));
+            return VERR_NOT_SUPPORTED;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int drvHostALSAAudioALSAGetShift(snd_pcm_format_t fmt, unsigned *puShift)
+{
+    AssertPtrReturn(puShift, VERR_INVALID_POINTER);
+
+    switch (fmt)
+    {
+        case SND_PCM_FORMAT_S8:
+        case SND_PCM_FORMAT_U8:
+            *puShift = 0;
+            break;
+
+        case SND_PCM_FORMAT_S16_LE:
+        case SND_PCM_FORMAT_U16_LE:
+        case SND_PCM_FORMAT_S16_BE:
+        case SND_PCM_FORMAT_U16_BE:
+            *puShift = 1;
+            break;
+
+        case SND_PCM_FORMAT_S32_LE:
+        case SND_PCM_FORMAT_U32_LE:
+        case SND_PCM_FORMAT_S32_BE:
+        case SND_PCM_FORMAT_U32_BE:
+            *puShift = 2;
+            break;
+
+        default:
+            AssertMsgFailed(("Format %ld not supported\n", fmt));
+            return VERR_NOT_SUPPORTED;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int drvHostALSAAudioSetThreshold(snd_pcm_t *phPCM,
+                                        snd_pcm_uframes_t threshold)
+{
+    snd_pcm_sw_params_t *pSWParms = NULL;
+    snd_pcm_sw_params_alloca(&pSWParms);
+    if (!pSWParms)
+        return VERR_NO_MEMORY;
+
+    int rc;
+    do
+    {
+        int err = snd_pcm_sw_params_current(phPCM, pSWParms);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to get current software parameters for threshold: %s\n",
+                    snd_strerror(err)));
+            rc = VERR_ACCESS_DENIED;
+            break;
+        }
+
+        err = snd_pcm_sw_params_set_start_threshold(phPCM, pSWParms, threshold);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set software threshold to %ld: %s\n",
+                    threshold, snd_strerror(err)));
+            rc = VERR_ACCESS_DENIED;
+            break;
+        }
+
+        err = snd_pcm_sw_params(phPCM, pSWParms);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set new software parameters for threshold: %s\n",
+                    snd_strerror(err)));
+            rc = VERR_ACCESS_DENIED;
+            break;
+        }
+
+        LogFlowFunc(("Setting threshold to %RU32\n", threshold));
+        rc = VINF_SUCCESS;
+    }
+    while (0);
+
+    return rc;
+}
+
+static int drvHostALSAAudioOpen(bool fIn,
+                                PALSAAUDIOSTREAMCFG pCfgReq,
+                                PALSAAUDIOSTREAMCFG pCfgObt,
+                                snd_pcm_t **pphPCM)
+{
+    snd_pcm_t *phPCM = NULL;
+    int rc;
+
+    unsigned int cChannels = pCfgReq->nchannels;
+    unsigned int uFreq = pCfgReq->freq;
+    snd_pcm_uframes_t obt_buffer_size;
+
+    do
+    {
+        const char *pszDev = fIn ? s_ALSAConf.pcm_name_in : s_ALSAConf.pcm_name_out;
+        if (!pszDev)
+        {
+            LogRel(("ALSA: Invalid or no %s device name set\n", fIn ? "input" : "output"));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+        }
+
+        int err = snd_pcm_open(&phPCM, pszDev,
+                               fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
+                               SND_PCM_NONBLOCK);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to open \"%s\" as %s device: %s\n", pszDev, fIn ? "input" : "output", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        LogRel(("ALSA: Using %s device \"%s\"\n", fIn ? "input" : "output", pszDev));
+
+        snd_pcm_hw_params_t *pHWParms;
+        snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */
+        err = snd_pcm_hw_params_any(phPCM, pHWParms);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to initialize hardware parameters: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        err = snd_pcm_hw_params_set_access(phPCM, pHWParms,
+                                           SND_PCM_ACCESS_RW_INTERLEAVED);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set audio format to %d: %s\n", pCfgReq->fmt, snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set frequency to %uHz: %s\n", pCfgReq->freq, snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        if (   cChannels != 1
+            && cChannels != 2)
+        {
+            LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        unsigned int period_size = pCfgReq->period_size;
+        unsigned int buffer_size = pCfgReq->buffer_size;
+
+        if (   !((fIn && s_ALSAConf.size_in_usec_in)
+            ||  (!fIn && s_ALSAConf.size_in_usec_out)))
+        {
+            if (!buffer_size)
+            {
+                buffer_size = DEFAULT_BUFFER_SIZE;
+                period_size = DEFAULT_PERIOD_SIZE;
+            }
+        }
+
+        if (buffer_size)
+        {
+            if (   ( fIn && s_ALSAConf.size_in_usec_in)
+                || (!fIn && s_ALSAConf.size_in_usec_out))
+            {
+                if (period_size)
+                {
+                    err = snd_pcm_hw_params_set_period_time_near(phPCM, pHWParms,
+                                                                 &period_size, 0);
+                    if (err < 0)
+                    {
+                        LogRel(("ALSA: Failed to set period time %d\n", pCfgReq->period_size));
+                        rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                        break;
+                    }
+                }
+
+                err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pHWParms,
+                                                             &buffer_size, 0);
+                if (err < 0)
+                {
+                    LogRel(("ALSA: Failed to set buffer time %d\n", pCfgReq->buffer_size));
+                    rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                    break;
+                }
+            }
+            else
+            {
+                snd_pcm_uframes_t period_size_f = (snd_pcm_uframes_t)period_size;
+                snd_pcm_uframes_t buffer_size_f = (snd_pcm_uframes_t)buffer_size;
+
+                snd_pcm_uframes_t minval;
+
+                if (period_size_f)
+                {
+                    minval = period_size_f;
+
+                    int dir = 0;
+                    err = snd_pcm_hw_params_get_period_size_min(pHWParms,
+                                                                &minval, &dir);
+                    if (err < 0)
+                    {
+                        LogRel(("ALSA: Could not determine minimal period size\n"));
+                        rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                        break;
+                    }
+                    else
+                    {
+                        LogFunc(("Minimal period size is: %ld\n", minval));
+                        if (period_size_f < minval)
+                        {
+                            if (   ( fIn && s_ALSAConf.period_size_in_overriden)
+                                || (!fIn && s_ALSAConf.period_size_out_overriden))
+                            {
+                                LogFunc(("Period size %RU32 is less than minimal period size %RU32\n",
+                                         period_size_f, minval));
+                            }
+
+                            period_size_f = minval;
+                        }
+                    }
+
+                    err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms,
+                                                                 &period_size_f, 0);
+                    LogFunc(("Period size is: %RU32\n", period_size_f));
+                    if (err < 0)
+                    {
+                        LogRel(("ALSA: Failed to set period size %d (%s)\n",
+                                period_size_f, snd_strerror(err)));
+                        rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                        break;
+                    }
+                }
+
+                /* Calculate default buffer size here since it might have been changed
+                 * in the _near functions */
+                buffer_size_f = 4 * period_size_f;
+
+                minval = buffer_size_f;
+                err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval);
+                if (err < 0)
+                {
+                    LogRel(("ALSA: Could not retrieve minimal buffer size\n"));
+                    rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                    break;
+                }
+                else
+                {
+                    LogFunc(("Minimal buffer size is: %RU32\n", minval));
+                    if (buffer_size_f < minval)
+                    {
+                        if (   ( fIn && s_ALSAConf.buffer_size_in_overriden)
+                            || (!fIn && s_ALSAConf.buffer_size_out_overriden))
+                        {
+                            LogFunc(("Buffer size %RU32 is less than minimal buffer size %RU32\n",
+                                     buffer_size_f, minval));
+                        }
+
+                        buffer_size_f = minval;
+                    }
+                }
+
+                err = snd_pcm_hw_params_set_buffer_size_near(phPCM,
+                                                             pHWParms, &buffer_size_f);
+                LogFunc(("Buffer size is: %RU32\n", buffer_size_f));
+                if (err < 0)
+                {
+                    LogRel(("ALSA: Failed to set buffer size %d: %s\n",
+                            buffer_size_f, snd_strerror(err)));
+                    rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                    break;
+                }
+            }
+        }
+        else
+            LogFunc(("Warning: Buffer size is not set\n"));
+
+        err = snd_pcm_hw_params(phPCM, pHWParms);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to apply audio parameters\n"));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to get buffer size\n"));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        snd_pcm_uframes_t obt_period_size;
+        int dir = 0;
+        err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to get period size\n"));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        LogFunc(("Freq=%dHz, period size=%RU32, buffer size=%RU32\n",
+                 pCfgReq->freq, obt_period_size, obt_buffer_size));
+
+        err = snd_pcm_prepare(phPCM);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        if (   !fIn
+            && s_ALSAConf.threshold)
+        {
+            unsigned uShift;
+            rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
+            if (RT_SUCCESS(rc))
+            {
+                int bytes_per_sec = uFreq
+                    << (cChannels == 2)
+                    << uShift;
+
+                snd_pcm_uframes_t threshold
+                    = (s_ALSAConf.threshold * bytes_per_sec) / 1000;
+
+                rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
+            }
+        }
+        else
+            rc = VINF_SUCCESS;
+    }
+    while (0);
+
+    if (RT_SUCCESS(rc))
+    {
+        pCfgObt->fmt       = pCfgReq->fmt;
+        pCfgObt->nchannels = cChannels;
+        pCfgObt->freq      = uFreq;
+        pCfgObt->samples   = obt_buffer_size;
+
+        *pphPCM = phPCM;
+    }
+    else
+        drvHostALSAAudioClose(&phPCM);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+#ifdef DEBUG
+static void drvHostALSAAudioErrorHandler(const char *file, int line, const char *function,
+                                         int err, const char *fmt, ...)
+{
+    RT_NOREF(file, line, function, err, fmt);
+    /** @todo Implement me! */
+}
+#endif
+
+static int drvHostALSAAudioGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
+{
+    AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
+    AssertPtrReturn(pFramesAvail, VERR_INVALID_POINTER);
+
+    int rc;
+
+    snd_pcm_sframes_t framesAvail;
+    framesAvail = snd_pcm_avail_update(phPCM);
+    if (framesAvail < 0)
+    {
+        if (framesAvail == -EPIPE)
+        {
+            rc = drvHostALSAAudioRecover(phPCM);
+            if (RT_SUCCESS(rc))
+                framesAvail = snd_pcm_avail_update(phPCM);
+        }
+        else
+            rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    if (framesAvail >= 0)
+        *pFramesAvail = framesAvail;
+
+    return rc;
+}
+
+static int drvHostALSAAudioRecover(snd_pcm_t *phPCM)
+{
+    AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
+
+    int err = snd_pcm_prepare(phPCM);
+    if (err < 0)
+    {
+        LogFunc(("Failed to recover stream %p: %s\n", phPCM, snd_strerror(err)));
+        return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int drvHostALSAAudioResume(snd_pcm_t *phPCM)
+{
+    AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
+
+    int err = snd_pcm_resume(phPCM);
+    if (err < 0)
+    {
+        LogFunc(("Failed to resume stream %p: %s\n", phPCM, snd_strerror(err)));
+        return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int drvHostALSAAudioStreamCtl(snd_pcm_t *phPCM, bool fPause)
+{
+    int err;
+    if (fPause)
+    {
+        err = snd_pcm_drop(phPCM);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Error stopping stream %p: %s\n", phPCM, snd_strerror(err)));
+            return VERR_ACCESS_DENIED;
+        }
+    }
+    else
+    {
+        err = snd_pcm_prepare(phPCM);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Error preparing stream %p: %s\n", phPCM, snd_strerror(err)));
+            return VERR_ACCESS_DENIED;
+        }
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioInit(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    LogFlowFuncEnter();
+
+    int rc = audioLoadAlsaLib();
+    if (RT_FAILURE(rc))
+        LogRel(("ALSA: Failed to load the ALSA shared library, rc=%Rrc\n", rc));
+    else
+    {
+#ifdef DEBUG
+        snd_lib_error_set_handler(drvHostALSAAudioErrorHandler);
+#endif
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   uint32_t *pcSamplesCaptured)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
+
+    snd_pcm_sframes_t cAvail;
+    int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
+    if (RT_FAILURE(rc))
+    {
+        LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
+        return rc;
+    }
+
+    if (!cAvail) /* No data yet? */
+    {
+        snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
+        switch (state)
+        {
+            case SND_PCM_STATE_PREPARED:
+                cAvail = AudioMixBufFree(&pHstStrmIn->MixBuf);
+                break;
+
+            case SND_PCM_STATE_SUSPENDED:
+            {
+                rc = drvHostALSAAudioResume(pThisStrmIn->phPCM);
+                if (RT_FAILURE(rc))
+                    break;
+
+                LogFlow(("Resuming suspended input stream\n"));
+                break;
+            }
+
+            default:
+                LogFlow(("No frames available, state=%d\n", state));
+                break;
+        }
+
+        if (!cAvail)
+        {
+            if (pcSamplesCaptured)
+                *pcSamplesCaptured = 0;
+            return VINF_SUCCESS;
+        }
+    }
+
+    /*
+     * Check how much we can read from the capture device without overflowing
+     * the mixer buffer.
+     */
+    Assert(cAvail);
+    size_t cbMixFree = AudioMixBufFreeBytes(&pHstStrmIn->MixBuf);
+    size_t cbToRead = RT_MIN((size_t)AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail), cbMixFree);
+
+    LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));
+
+    uint32_t cWrittenTotal = 0;
+    snd_pcm_uframes_t cToRead;
+    snd_pcm_sframes_t cRead;
+
+    while (   cbToRead
+           && RT_SUCCESS(rc))
+    {
+        cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
+                         AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
+        AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
+        cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
+        if (cRead <= 0)
+        {
+            switch (cRead)
+            {
+                case 0:
+                {
+                    LogFunc(("No input frames available\n"));
+                    rc = VERR_ACCESS_DENIED;
+                    break;
+                }
+
+                case -EAGAIN:
+                {
+                    /*
+                     * Don't set error here because EAGAIN means there are no further frames
+                     * available at the moment, try later. As we might have read some frames
+                     * already these need to be processed instead.
+                     */
+                    cbToRead = 0;
+                    break;
+                }
+
+                case -EPIPE:
+                {
+                    rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
+                    if (RT_FAILURE(rc))
+                        break;
+
+                    LogFlowFunc(("Recovered from capturing\n"));
+                    continue;
+                }
+
+                default:
+                {
+                    LogFunc(("Failed to read input frames: %s\n", snd_strerror(cRead)));
+                    rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
+                    break;
+                }
+            }
+        }
+        else
+        {
+            uint32_t cWritten;
+            rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
+                                      pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
+                                      &cWritten);
+            if (RT_FAILURE(rc))
+                break;
+
+            /*
+             * We should not run into a full mixer buffer or we loose samples and
+             * run into an endless loop if ALSA keeps producing samples ("null"
+             * capture device for example).
+             */
+            AssertLogRelMsgBreakStmt(cWritten > 0, ("Mixer buffer shouldn't be full at this point!\n"),
+                                     rc = VERR_INTERNAL_ERROR);
+            uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
+
+            Assert(cbToRead >= cbWritten);
+            cbToRead -= cbWritten;
+            cWrittenTotal += cWritten;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cProcessed = 0;
+        if (cWrittenTotal)
+            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
+                                        &cProcessed);
+
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cWrittenTotal;
+
+        LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
+                     cWrittenTotal, cProcessed, rc));
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                 uint32_t *pcSamplesPlayed)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
+
+    int rc = VINF_SUCCESS;
+    uint32_t cbReadTotal = 0;
+
+    do
+    {
+        snd_pcm_sframes_t cAvail;
+        rc = drvHostALSAAudioGetAvail(pThisStrmOut->phPCM, &cAvail);
+        if (RT_FAILURE(rc))
+        {
+            LogFunc(("Error getting number of playback frames, rc=%Rrc\n", rc));
+            break;
+        }
+
+        size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
+                                                 (uint32_t)cAvail), /* cAvail is always >= 0 */
+                                 AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
+                                                 AudioMixBufAvail(&pHstStrmOut->MixBuf)));
+        LogFlowFunc(("cbToRead=%zu, cbAvail=%zu\n",
+                     cbToRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail)));
+
+        uint32_t cRead, cbRead;
+        snd_pcm_sframes_t cWritten;
+        while (cbToRead)
+        {
+            rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvBuf, cbToRead, &cRead);
+            if (RT_FAILURE(rc))
+                break;
+
+            cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
+            AssertBreak(cbRead);
+
+            /* Don't try infinitely on recoverable errors. */
+            unsigned iTry;
+            for (iTry = 0; iTry < ALSA_RECOVERY_TRIES_MAX; iTry++)
+            {
+                cWritten = snd_pcm_writei(pThisStrmOut->phPCM, pThisStrmOut->pvBuf, cRead);
+                if (cWritten <= 0)
+                {
+                    switch (cWritten)
+                    {
+                        case 0:
+                        {
+                            LogFunc(("Failed to write %RI32 frames\n", cRead));
+                            rc = VERR_ACCESS_DENIED;
+                            break;
+                        }
+
+                        case -EPIPE:
+                        {
+                            rc = drvHostALSAAudioRecover(pThisStrmOut->phPCM);
+                            if (RT_FAILURE(rc))
+                                break;
+
+                            LogFlowFunc(("Recovered from playback\n"));
+                            continue;
+                        }
+
+                        case -ESTRPIPE:
+                        {
+                            /* Stream was suspended and waiting for a recovery. */
+                            rc = drvHostALSAAudioResume(pThisStrmOut->phPCM);
+                            if (RT_FAILURE(rc))
+                            {
+                                LogRel(("ALSA: Failed to resume output stream\n"));
+                                break;
+                            }
+
+                            LogFlowFunc(("Resumed suspended output stream\n"));
+                            continue;
+                        }
+
+                        default:
+                            LogFlowFunc(("Failed to write %RI32 output frames, rc=%Rrc\n",
+                                         cRead, rc));
+                            rc = VERR_GENERAL_FAILURE; /** @todo */
+                            break;
+                    }
+                }
+                else
+                    break;
+            } /* For number of tries. */
+
+            if (   iTry == ALSA_RECOVERY_TRIES_MAX
+                && cWritten <= 0)
+                rc = VERR_BROKEN_PIPE;
+
+            if (RT_FAILURE(rc))
+                break;
+
+            Assert(cbToRead >= cbRead);
+            cbToRead -= cbRead;
+            cbReadTotal += cbRead;
+        }
+    }
+    while (0);
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
+        if (cReadTotal)
+            AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
+
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = cReadTotal;
+
+        LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
+                     cReadTotal, cbReadTotal, rc));
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
+
+    drvHostALSAAudioClose(&pThisStrmIn->phPCM);
+
+    if (pThisStrmIn->pvBuf)
+    {
+        RTMemFree(pThisStrmIn->pvBuf);
+        pThisStrmIn->pvBuf = NULL;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
+
+    drvHostALSAAudioClose(&pThisStrmOut->phPCM);
+
+    if (pThisStrmOut->pvBuf)
+    {
+        RTMemFree(pThisStrmOut->pvBuf);
+        pThisStrmOut->pvBuf = NULL;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioInitOut(PPDMIHOSTAUDIO pInterface,
+                                                 PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                 uint32_t *pcSamples)
+{
+    RT_NOREF(pInterface, pCfgAcq);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,     VERR_INVALID_POINTER);
+
+    PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
+    snd_pcm_t *phPCM = NULL;
+
+    int rc;
+
+    do
+    {
+        ALSAAUDIOSTREAMCFG req;
+        req.fmt         = drvHostALSAAudioFmtToALSA(pCfgReq->enmFormat);
+        req.freq        = pCfgReq->uHz;
+        req.nchannels   = pCfgReq->cChannels;
+        req.period_size = s_ALSAConf.period_size_out;
+        req.buffer_size = s_ALSAConf.buffer_size_out;
+
+        ALSAAUDIOSTREAMCFG obt;
+        rc = drvHostALSAAudioOpen(false /* false */, &req, &obt, &phPCM);
+        if (RT_FAILURE(rc))
+            break;
+
+        PDMAUDIOFMT enmFormat;
+        PDMAUDIOENDIANNESS enmEnd;
+        rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
+        if (RT_FAILURE(rc))
+            break;
+
+        PDMAUDIOSTREAMCFG streamCfg;
+        streamCfg.uHz           = obt.freq;
+        streamCfg.cChannels     = obt.nchannels;
+        streamCfg.enmFormat     = enmFormat;
+        streamCfg.enmEndianness = enmEnd;
+
+        rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
+        if (RT_FAILURE(rc))
+            break;
+
+        AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
+        size_t cbBuf = obt.samples * (1 << pHstStrmOut->Props.cShift);
+        AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
+        pThisStrmOut->pvBuf = RTMemAlloc(cbBuf);
+        if (!pThisStrmOut->pvBuf)
+        {
+            LogRel(("ALSA: Not enough memory for output DAC buffer (%RU32 samples, each %d bytes)\n",
+                    obt.samples, 1 << pHstStrmOut->Props.cShift));
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        pThisStrmOut->cbBuf       = cbBuf;
+        pThisStrmOut->phPCM       = phPCM;
+
+        if (pcSamples)
+            *pcSamples = obt.samples;
+    }
+    while (0);
+
+    if (RT_FAILURE(rc))
+        drvHostALSAAudioClose(&phPCM);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
+                                                PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
+{
+    RT_NOREF(pInterface, pCfgAcq, enmRecSource);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
+
+    int rc;
+
+    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
+    snd_pcm_t *phPCM = NULL;
+
+    do
+    {
+        ALSAAUDIOSTREAMCFG req;
+        req.fmt         = drvHostALSAAudioFmtToALSA(pCfgReq->enmFormat);
+        req.freq        = pCfgReq->uHz;
+        req.nchannels   = pCfgReq->cChannels;
+        req.period_size = s_ALSAConf.period_size_in;
+        req.buffer_size = s_ALSAConf.buffer_size_in;
+
+        ALSAAUDIOSTREAMCFG obt;
+        rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
+        if (RT_FAILURE(rc))
+            break;
+
+        PDMAUDIOFMT enmFormat;
+        PDMAUDIOENDIANNESS enmEnd;
+        rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
+        if (RT_FAILURE(rc))
+            break;
+
+        PDMAUDIOSTREAMCFG streamCfg;
+        streamCfg.uHz           = obt.freq;
+        streamCfg.cChannels     = obt.nchannels;
+        streamCfg.enmFormat     = enmFormat;
+        streamCfg.enmEndianness = enmEnd;
+
+        rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
+        if (RT_FAILURE(rc))
+            break;
+
+        AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
+        size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
+        AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
+        pThisStrmIn->pvBuf = RTMemAlloc(cbBuf);
+        if (!pThisStrmIn->pvBuf)
+        {
+            LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
+                    obt.samples, 1 << pHstStrmIn->Props.cShift));
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        pThisStrmIn->cbBuf       = cbBuf;
+        pThisStrmIn->phPCM       = phPCM;
+
+        if (pcSamples)
+            *pcSamples = obt.samples;
+    }
+    while (0);
+
+    if (RT_FAILURE(rc))
+        drvHostALSAAudioClose(&phPCM);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvHostALSAAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    NOREF(pInterface);
+    NOREF(enmDir);
+    return true; /* Always all enabled. */
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
+
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    int rc;
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+            rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, false /* fStop */);
+            break;
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+            rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, true /* fStop */);
+            break;
+
+        default:
+            AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                    PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
+
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    int rc;
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+            rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, false /* fStop */);
+            break;
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+            rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, true /* fStop */);
+            break;
+
+        default:
+            AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    pCfg->cbStreamIn      = sizeof(ALSAAUDIOSTREAMIN);
+    pCfg->cbStreamOut     = sizeof(ALSAAUDIOSTREAMOUT);
+
+    /* ALSA only allows one input and one output used at a time for
+     * the selected device. */
+    pCfg->cMaxHstStrmsIn  = 1;
+    pCfg->cMaxHstStrmsOut = 1;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) drvHostALSAAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTALSAAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+
+    return NULL;
+}
+
+/**
+ * Construct a DirectSound Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(pCfg, fFlags);
+    PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
+    LogRel(("Audio: Initializing ALSA driver\n"));
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostALSAAudioQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostALSAAudio);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Char driver registration record.
+ */
+const PDMDRVREG g_DrvHostALSAAudio =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "ALSAAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "ALSA host audio driver",
+    /* fFlags */
+     PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTALSAAUDIO),
+    /* pfnConstruct */
+    drvHostAlsaAudioConstruct,
+    /* pfnDestruct */
+    NULL,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
+#if 0 // unused
+static struct audio_option alsa_options[] =
+{
+    {"DACSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_out,
+     "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
+    {"DACPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_out,
+     "DAC period size", &s_ALSAConf.period_size_out_overriden, 0},
+    {"DACBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_out,
+     "DAC buffer size", &s_ALSAConf.buffer_size_out_overriden, 0},
+
+    {"ADCSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_in,
+     "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
+    {"ADCPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_in,
+     "ADC period size", &s_ALSAConf.period_size_in_overriden, 0},
+    {"ADCBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_in,
+     "ADC buffer size", &s_ALSAConf.buffer_size_in_overriden, 0},
+
+    {"Threshold", AUD_OPT_INT, &s_ALSAConf.threshold,
+     "(undocumented)", NULL, 0},
+
+    {"DACDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_out,
+     "DAC device name (for instance dmix)", NULL, 0},
+
+    {"ADCDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_in,
+     "ADC device name", NULL, 0},
+
+    NULL
+};
+#endif
diff --git a/src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp
new file mode 100644
index 0000000..f2f854e
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp
@@ -0,0 +1,2278 @@
+/* $Id: DrvHostCoreAudio.cpp $ */
+/** @file
+ * VBox audio devices: Mac OS X CoreAudio audio driver.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+#include "VBoxDD.h"
+
+#include <iprt/asm.h>
+#include <iprt/cdefs.h>
+#include <iprt/circbuf.h>
+#include <iprt/mem.h>
+
+#include <iprt/uuid.h>
+
+#include <CoreAudio/CoreAudio.h>
+#include <CoreServices/CoreServices.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioConverter.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#if 0
+# include <iprt/file.h>
+# define DEBUG_DUMP_PCM_DATA
+# ifdef RT_OS_WINDOWS
+#  define DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# else
+#  define DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+# endif
+#endif
+
+/* Enables utilizing the Core Audio converter unit for converting
+ * input / output from/to our requested formats. That might be more
+ * performant than using our own routines later down the road. */
+/** @todo Needs more investigation and testing first before enabling. */
+//# define VBOX_WITH_AUDIO_CA_CONVERTER
+
+#ifdef DEBUG_andy
+# undef  DEBUG_DUMP_PCM_DATA_PATH
+# define DEBUG_DUMP_PCM_DATA_PATH "/Users/anloeffl/Documents/"
+# undef  VBOX_WITH_AUDIO_CA_CONVERTER
+#endif
+
+/* TODO:
+ * - Maybe make sure the threads are immediately stopped if playing/recording stops.
+ */
+
+/*
+ * Most of this is based on:
+ * http://developer.apple.com/mac/library/technotes/tn2004/tn2097.html
+ * http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html
+ * http://developer.apple.com/mac/library/qa/qa2007/qa1533.html
+ * http://developer.apple.com/mac/library/qa/qa2001/qa1317.html
+ * http://developer.apple.com/mac/library/documentation/AudioUnit/Reference/AUComponentServicesReference/Reference/reference.html
+ */
+
+/**
+ * Host Coreaudio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTCOREAUDIO
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS    pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO IHostAudio;
+} DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO;
+
+/*******************************************************************************
+ *
+ * Helper function section
+ *
+ ******************************************************************************/
+
+static void drvHostCoreAudioPrintASBD(const char *pszDesc, const AudioStreamBasicDescription *pASBD)
+{
+    char pszSampleRate[32];
+    LogRel2(("CoreAudio: %s description:\n", pszDesc));
+    LogRel2(("CoreAudio:\tFormat ID: %RU32 (%c%c%c%c)\n", pASBD->mFormatID,
+             RT_BYTE4(pASBD->mFormatID), RT_BYTE3(pASBD->mFormatID),
+             RT_BYTE2(pASBD->mFormatID), RT_BYTE1(pASBD->mFormatID)));
+    LogRel2(("CoreAudio:\tFlags: %RU32", pASBD->mFormatFlags));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsFloat)
+        LogRel2((" Float"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsBigEndian)
+        LogRel2((" BigEndian"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsSignedInteger)
+        LogRel2((" SignedInteger"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsPacked)
+        LogRel2((" Packed"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsAlignedHigh)
+        LogRel2((" AlignedHigh"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsNonInterleaved)
+        LogRel2((" NonInterleaved"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsNonMixable)
+        LogRel2((" NonMixable"));
+    if (pASBD->mFormatFlags & kAudioFormatFlagsAreAllClear)
+        LogRel2((" AllClear"));
+    LogRel2(("\n"));
+    snprintf(pszSampleRate, 32, "%.2f", (float)pASBD->mSampleRate); /** @todo r=andy Use RTStrPrint*. */
+    LogRel2(("CoreAudio:\tSampleRate      : %s\n", pszSampleRate));
+    LogRel2(("CoreAudio:\tChannelsPerFrame: %RU32\n", pASBD->mChannelsPerFrame));
+    LogRel2(("CoreAudio:\tFramesPerPacket : %RU32\n", pASBD->mFramesPerPacket));
+    LogRel2(("CoreAudio:\tBitsPerChannel  : %RU32\n", pASBD->mBitsPerChannel));
+    LogRel2(("CoreAudio:\tBytesPerFrame   : %RU32\n", pASBD->mBytesPerFrame));
+    LogRel2(("CoreAudio:\tBytesPerPacket  : %RU32\n", pASBD->mBytesPerPacket));
+}
+
+static int drvHostCoreAudioPCMPropsToASBD(PPDMPCMPROPS pPCMProps, AudioStreamBasicDescription *pASBD)
+{
+    AssertPtrReturn(pPCMProps, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pASBD,     VERR_INVALID_PARAMETER);
+
+    RT_BZERO(pASBD, sizeof(AudioStreamBasicDescription));
+
+    pASBD->mFormatID         = kAudioFormatLinearPCM;
+    pASBD->mFormatFlags      = kAudioFormatFlagIsPacked;
+    pASBD->mFramesPerPacket  = 1; /* For uncompressed audio, set this to 1. */
+    pASBD->mSampleRate       = (Float64)pPCMProps->uHz;
+    pASBD->mChannelsPerFrame = pPCMProps->cChannels;
+    pASBD->mBitsPerChannel   = pPCMProps->cBits;
+    if (pPCMProps->fSigned)
+        pASBD->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
+    pASBD->mBytesPerFrame    = pASBD->mChannelsPerFrame * (pASBD->mBitsPerChannel / 8);
+    pASBD->mBytesPerPacket   = pASBD->mFramesPerPacket * pASBD->mBytesPerFrame;
+
+    return VINF_SUCCESS;
+}
+
+static int drvHostCoreAudioStreamCfgToASBD(PPDMAUDIOSTREAMCFG pCfg, AudioStreamBasicDescription *pASBD)
+{
+    AssertPtrReturn(pCfg,  VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
+
+    PDMPCMPROPS Props;
+    int rc = DrvAudioStreamCfgToProps(pCfg, &Props);
+    if (RT_SUCCESS(rc))
+        rc = drvHostCoreAudioPCMPropsToASBD(&Props, pASBD);
+
+    return rc;
+}
+
+static int drvHostCoreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pCfg,  VERR_INVALID_PARAMETER);
+
+    pCfg->cChannels     = pASBD->mChannelsPerFrame;
+    pCfg->uHz           = (uint32_t)pASBD->mSampleRate;
+    pCfg->enmEndianness = PDMAUDIOENDIANNESS_LITTLE;
+
+    int rc = VINF_SUCCESS;
+
+    if (pASBD->mFormatFlags & kAudioFormatFlagIsSignedInteger)
+    {
+        switch (pASBD->mBitsPerChannel)
+        {
+            case 8:  pCfg->enmFormat = AUD_FMT_S8;  break;
+            case 16: pCfg->enmFormat = AUD_FMT_S16; break;
+            case 32: pCfg->enmFormat = AUD_FMT_S32; break;
+            default: rc = VERR_NOT_SUPPORTED;       break;
+        }
+    }
+    else
+    {
+        switch (pASBD->mBitsPerChannel)
+        {
+            case 8:  pCfg->enmFormat = AUD_FMT_U8;  break;
+            case 16: pCfg->enmFormat = AUD_FMT_U16; break;
+            case 32: pCfg->enmFormat = AUD_FMT_U32; break;
+            default: rc = VERR_NOT_SUPPORTED;       break;
+        }
+    }
+
+    AssertRC(rc);
+    return rc;
+}
+
+#if 0 // unused
+static AudioDeviceID drvHostCoreAudioDeviceUIDtoID(const char* pszUID)
+{
+    /* Create a CFString out of our CString. */
+    CFStringRef strUID = CFStringCreateWithCString(NULL, pszUID, kCFStringEncodingMacRoman);
+
+    /* Fill the translation structure. */
+    AudioDeviceID deviceID;
+
+    AudioValueTranslation translation;
+    translation.mInputData      = &strUID;
+    translation.mInputDataSize  = sizeof(CFStringRef);
+    translation.mOutputData     = &deviceID;
+    translation.mOutputDataSize = sizeof(AudioDeviceID);
+
+    /* Fetch the translation from the UID to the device ID. */
+    AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDeviceForUID, kAudioObjectPropertyScopeGlobal,
+                                           kAudioObjectPropertyElementMaster };
+
+    UInt32 uSize = sizeof(AudioValueTranslation);
+    OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &translation);
+
+    /* Release the temporary CFString */
+    CFRelease(strUID);
+
+    if (RT_LIKELY(err == noErr))
+        return deviceID;
+
+    /* Return the unknown device on error. */
+    return kAudioDeviceUnknown;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Global structures section
+ *
+ ******************************************************************************/
+
+/* Initialization status indicator used for the recreation of the AudioUnits. */
+#define CA_STATUS_UNINIT    UINT32_C(0) /* The device is uninitialized */
+#define CA_STATUS_IN_INIT   UINT32_C(1) /* The device is currently initializing */
+#define CA_STATUS_INIT      UINT32_C(2) /* The device is initialized */
+#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
+#define CA_STATUS_REINIT    UINT32_C(4) /* The device has to be reinitialized */
+
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+/* Error code which indicates "End of data" */
+static const OSStatus caConverterEOFDErr = 0x656F6664; /* 'eofd' */
+#endif
+
+/* Prototypes needed for COREAUDIOSTREAMCBCTX. */
+struct COREAUDIOSTREAMIN;
+typedef struct COREAUDIOSTREAMIN *PCOREAUDIOSTREAMIN;
+struct COREAUDIOSTREAMOUT;
+typedef struct COREAUDIOSTREAMOUT *PCOREAUDIOSTREAMOUT;
+
+typedef struct COREAUDIOSTREAM
+{
+    /** The stream's direction. */
+    PDMAUDIODIR                 enmDir;
+    union
+    {
+        /** Pointer to self, if it's an input stream. */
+        PCOREAUDIOSTREAMIN      pIn;
+        /** Pointer to self, if it's an output stream. */
+        PCOREAUDIOSTREAMOUT     pOut;
+        /** @todo Add attributes here as soon as COREAUDIOSTREAMIN / COREAUDIOSTREAMOUT are unified. */
+    };
+    /** The stream's thread handle for maintaining the audio queue. */
+    RTTHREAD                    hThread;
+    /** Flag indicating to start a stream's data processing. */
+    bool                        fRun;
+    /** Whether the stream is in a running (active) state or not.
+     *  For playback streams this means that audio data can be (or is being) played,
+     *  for capturing streams this means that audio data is being captured (if available). */
+    bool                        fIsRunning;
+    /** Thread shutdown indicator. */
+    bool                        fShutdown;
+    /** Critical section for serializing access between thread + callbacks. */
+    RTCRITSECT                  CritSect;
+    /** The actual audio queue being used. */
+    AudioQueueRef               audioQueue;
+    /** The audio buffers which are used with the above audio queue. */
+    AudioQueueBufferRef         audioBuffer[3];
+    /** The acquired (final) audio format for this stream. */
+    AudioStreamBasicDescription asbdStream;
+    /** The device' UUID. */
+    CFStringRef                 UUID;
+    /** An internal ring buffer for transferring data from/to the rendering callbacks. */
+    PRTCIRCBUF                  pCircBuf;
+} COREAUDIOSTREAM, *PCOREAUDIOSTREAM;
+
+/**
+ * Simple structure for maintaining a stream's callback context.
+ */
+typedef struct COREAUDIOSTREAMCBCTX
+{
+    /** Pointer to driver instance. */
+    PDRVHOSTCOREAUDIO pThis;
+    /** Pointer to the stream being handled. Can be NULL if not used. */
+    PCOREAUDIOSTREAM  pStream;
+} COREAUDIOSTREAMCBCTX, *PCOREAUDIOSTREAMCBCTX;
+
+/**
+ * Structure for keeping a conversion callback context.
+ * This is needed when using an audio converter during input/output processing.
+ */
+typedef struct COREAUDIOCONVCBCTX
+{
+    /** Pointer to stream context this converter callback context
+     *  is bound to. */
+    /** @todo Remove this as soon as we have unified input/output streams in this backend. */
+    PCOREAUDIOSTREAMCBCTX        pStreamCtx;
+    /** Source stream description. */
+    AudioStreamBasicDescription  asbdSrc;
+    /** Destination stream description. */
+    AudioStreamBasicDescription  asbdDst;
+    /** Pointer to native buffer list used for rendering the source audio data into. */
+    AudioBufferList             *pBufLstSrc;
+    /** Total packet conversion count. */
+    UInt32                       uPacketCnt;
+    /** Current packet conversion index. */
+    UInt32                       uPacketIdx;
+    /** Error count, for limiting the logging. */
+    UInt32                       cErrors;
+} COREAUDIOCONVCBCTX, *PCOREAUDIOCONVCBCTX;
+
+/** @todo Unify COREAUDIOSTREAMOUT / COREAUDIOSTREAMIN. */
+typedef struct COREAUDIOSTREAMOUT
+{
+    /** Host output stream.
+     *  Note: Always must come first in this structure! */
+    PDMAUDIOHSTSTRMOUT          streamOut;
+    /** The audio device ID of the currently used device. */
+    AudioDeviceID               deviceID;
+    /** The AudioUnit being used. */
+    AudioUnit                   audioUnit;
+    /** A ring buffer for transferring data to the playback thread. */
+    PRTCIRCBUF                  pCircBuf;
+    /** Initialization status tracker. Used when some of the device parameters
+     *  or the device itself is changed during the runtime. */
+    volatile uint32_t           status;
+    /** Flag whether the "default device changed" listener was registered. */
+    bool                        fDefDevChgListReg;
+    /** Flag whether the "device state changed" listener was registered. */
+    bool                        fDevStateChgListReg;
+    /** Unified attribtues. */
+    /** @todo Remove this as soon as we have unified input/output streams in this backend. */
+    COREAUDIOSTREAM             Stream;
+    /** Callback context for this stream for handing this stream in an CoreAudio callback.
+     ** @todo Remove this as soon as we have unified input/output streams in this backend. */
+    COREAUDIOSTREAMCBCTX        cbCtx;
+} COREAUDIOSTREAMOUT, *PCOREAUDIOSTREAMOUT;
+
+typedef struct COREAUDIOSTREAMIN
+{
+    /** Host input stream.
+     *  Note: Always must come first in this structure! */
+    PDMAUDIOHSTSTRMIN           streamIn;
+    /** The audio device ID of the currently used device. */
+    AudioDeviceID               deviceID;
+    /** The AudioUnit used. */
+    AudioUnit                   audioUnit;
+    /** A ring buffer for transferring data from the recording thread. */
+    PRTCIRCBUF                  pCircBuf;
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+    /** The audio converter if necessary. NULL if no converter is being used. */
+    AudioConverterRef           ConverterRef;
+    /** Callback context for the audio converter. */
+    COREAUDIOCONVCBCTX          convCbCtx;
+#endif
+    /** The ratio between the device & the stream sample rate. */
+    Float64                     sampleRatio;
+    /** Initialization status tracker. Used when some of the device parameters
+     *  or the device itself is changed during the runtime. */
+    volatile uint32_t           status;
+    /** Flag whether the "default device changed" listener was registered. */
+    bool                        fDefDevChgListReg;
+    /** Flag whether the "device state changed" listener was registered. */
+    bool                        fDevStateChgListReg;
+    /** Unified attribtues. */
+    /** @todo Remove this as soon as we have unified input/output streams in this backend. */
+    COREAUDIOSTREAM             Stream;
+    /** Callback context for this stream for handing this stream in an CoreAudio callback.
+     ** @todo Remove this as soon as we have unified input/output streams in this backend. */
+    COREAUDIOSTREAMCBCTX        cbCtx;
+} COREAUDIOSTREAMIN, *PCOREAUDIOSTREAMIN;
+
+static int drvHostCoreAudioReinitInput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+static int drvHostCoreAudioReinitOutput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+
+static int drvHostCoreAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd);
+static int drvHostCoreAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd);
+static int drvHostCoreAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+static int drvHostCoreAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+
+static OSStatus drvHostCoreAudioDevPropChgCb(AudioObjectID propertyID, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void *pvUser);
+
+static void coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer, const AudioTimeStamp *pAudioTS, UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc);
+static void coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer);
+
+
+/**
+ * Does a (Re-)enumeration of the host's playback + recording devices.
+ *
+ * @return  IPRT status code.
+ * @param   pThis               Host audio driver instance.
+ * @param   pCfg                Where to store the enumeration results.
+ * @param   fEnum               Enumeration flags.
+ */
+static int drvHostCoreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, bool fIn, uint32_t fEnum)
+{
+    RT_NOREF(fEnum);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    /* pCfg is optional. */
+
+    int rc = VINF_SUCCESS;
+
+    uint8_t cDevs = 0;
+
+    do
+    {
+        AudioObjectPropertyAddress propAdrDevList = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
+                                                      kAudioObjectPropertyElementMaster };
+        UInt32 uSize = 0;
+        OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propAdrDevList, 0, NULL, &uSize);
+        if (err != kAudioHardwareNoError)
+            break;
+
+        AudioDeviceID *pDevIDs = (AudioDeviceID *)alloca(uSize);
+        if (pDevIDs == NULL)
+            break;
+
+        err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdrDevList, 0, NULL, &uSize, pDevIDs);
+        if (err != kAudioHardwareNoError)
+            break;
+
+        UInt32 cDevices = uSize / sizeof (AudioDeviceID);
+        for (UInt32 i = 0; i < cDevices; i++)
+        {
+            AudioDeviceID curDevID = pDevIDs[i];
+
+            /* Check if the device is valid. */
+            AudioObjectPropertyAddress propAddrCfg = { kAudioDevicePropertyStreamConfiguration,
+                                                       fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+                                                       kAudioObjectPropertyElementMaster };
+
+            err = AudioObjectGetPropertyDataSize(curDevID, &propAddrCfg, 0, NULL, &uSize);
+            if (err != noErr)
+                continue;
+
+            AudioBufferList *pBufList = (AudioBufferList *)RTMemAlloc(uSize);
+            if (!pBufList)
+                continue;
+
+            bool fIsValid      = false;
+            uint16_t cChannels = 0;
+
+            err = AudioObjectGetPropertyData(curDevID, &propAddrCfg, 0, NULL, &uSize, pBufList);
+            if (err == noErr)
+            {
+                for (UInt32 a = 0; a < pBufList->mNumberBuffers; a++)
+                    cChannels += pBufList->mBuffers[a].mNumberChannels;
+
+                fIsValid = cChannels > 0;
+            }
+
+            if (pBufList)
+            {
+                RTMemFree(pBufList);
+                pBufList = NULL;
+            }
+
+            if (!fIsValid)
+                continue;
+
+            /* Resolve the device's name. */
+            AudioObjectPropertyAddress propAddrName = { kAudioObjectPropertyName,
+                                                        fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+                                                        kAudioObjectPropertyElementMaster };
+            uSize = sizeof(CFStringRef);
+            CFStringRef pcfstrName = NULL;
+
+            err = AudioObjectGetPropertyData(curDevID, &propAddrName, 0, NULL, &uSize, &pcfstrName);
+            if (err != kAudioHardwareNoError)
+                continue;
+
+            CFIndex uMax = CFStringGetMaximumSizeForEncoding(CFStringGetLength(pcfstrName), kCFStringEncodingUTF8) + 1;
+            if (uMax)
+            {
+                char *pszName = (char *)RTStrAlloc(uMax);
+                if (   pszName
+                    && CFStringGetCString(pcfstrName, pszName, uMax, kCFStringEncodingUTF8))
+                {
+                    LogRel2(("CoreAudio: Found %s device '%s' (%RU16 channels max)\n",
+                             fIn ? "recording" : "playback", pszName, cChannels));
+                    cDevs++;
+                }
+
+                if (pszName)
+                {
+                    RTStrFree(pszName);
+                    pszName = NULL;
+                }
+            }
+
+            CFRelease(pcfstrName);
+        }
+
+    } while (0);
+
+    if (fIn)
+        LogRel2(("CoreAudio: Found %RU8 recording device(s)\n", cDevs));
+    else
+        LogRel2(("CoreAudio: Found %RU8 playback device(s)\n", cDevs));
+
+    if (pCfg)
+    {
+        if (fIn)
+            pCfg->cMaxHstStrmsIn  = cDevs;
+        else
+            pCfg->cMaxHstStrmsOut = cDevs;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Updates this host driver's internal status, according to the global, overall input/output
+ * state and all connected (native) audio streams.
+ *
+ * @param   pThis               Host audio driver instance.
+ * @param   pCfg                Where to store the backend configuration. Optional.
+ * @param   fEnum               Enumeration flags.
+ */
+int coreAudioUpdateStatusInternalEx(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+{
+    RT_NOREF(fEnum);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    /* pCfg is optional. */
+
+    PDMAUDIOBACKENDCFG Cfg;
+    RT_ZERO(Cfg);
+
+    Cfg.cbStreamOut = sizeof(COREAUDIOSTREAMOUT);
+    Cfg.cbStreamIn  = sizeof(COREAUDIOSTREAMIN);
+
+    int rc = drvHostCoreAudioDevicesEnumerate(pThis, &Cfg, false /* fIn */, 0 /* fEnum */);
+    AssertRC(rc);
+    rc = drvHostCoreAudioDevicesEnumerate(pThis, &Cfg, true /* fIn */, 0 /* fEnum */);
+    AssertRC(rc);
+
+    if (pCfg)
+        memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(OSStatus) drvHostCoreAudioDeviceStateChangedCb(AudioObjectID propertyID,
+                                                                   UInt32 nAddresses,
+                                                                   const AudioObjectPropertyAddress properties[],
+                                                                   void *pvUser)
+{
+    RT_NOREF(propertyID, nAddresses, properties);
+    LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
+
+    PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
+    AssertPtr(pCbCtx);
+    AssertPtr(pCbCtx->pStream);
+
+    UInt32 uAlive = 1;
+    UInt32 uSize  = sizeof(UInt32);
+
+    AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+                                           kAudioObjectPropertyElementMaster };
+
+    AudioDeviceID deviceID = pCbCtx->pStream->enmDir == PDMAUDIODIR_IN
+                           ? pCbCtx->pStream->pIn->deviceID : pCbCtx->pStream->pOut->deviceID;
+
+    OSStatus err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &uAlive);
+
+    bool fIsDead = false;
+
+    if (err == kAudioHardwareBadDeviceError)
+        fIsDead = true; /* Unplugged. */
+    else if ((err == kAudioHardwareNoError) && (!RT_BOOL(uAlive)))
+        fIsDead = true; /* Something else happened. */
+
+    if (fIsDead)
+    {
+        switch (pCbCtx->pStream->enmDir)
+        {
+            case PDMAUDIODIR_IN:
+            {
+                PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
+
+                /* We move the reinitialization to the next output event.
+                 * This make sure this thread isn't blocked and the
+                 * reinitialization is done when necessary only. */
+                ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
+
+                LogRel(("CoreAudio: Recording device stopped functioning\n"));
+                break;
+            }
+
+            case PDMAUDIODIR_OUT:
+            {
+                PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
+
+                /* We move the reinitialization to the next output event.
+                 * This make sure this thread isn't blocked and the
+                 * reinitialization is done when necessary only. */
+                ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
+
+                LogRel(("CoreAudio: Playback device stopped functioning\n"));
+                break;
+            }
+
+            default:
+                AssertMsgFailed(("Not implemented\n"));
+                break;
+        }
+    }
+
+    int rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
+    AssertRC(rc2);
+    rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
+    AssertRC(rc2);
+
+    return noErr;
+}
+
+/* Callback for getting notified when the default recording/playback device has been changed. */
+static DECLCALLBACK(OSStatus) drvHostCoreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,
+                                                                     UInt32 nAddresses,
+                                                                     const AudioObjectPropertyAddress properties[],
+                                                                     void *pvUser)
+{
+    RT_NOREF(propertyID);
+    OSStatus err = noErr;
+
+    LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
+
+    PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
+    AssertPtr(pCbCtx);
+    AssertPtr(pCbCtx->pStream);
+
+    for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)
+    {
+        const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
+
+        switch (pProperty->mSelector)
+        {
+            case kAudioHardwarePropertyDefaultInputDevice:
+            {
+                PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
+                AssertPtr(pStreamIn);
+
+                /* This listener is called on every change of the hardware
+                 * device. So check if the default device has really changed. */
+                UInt32 uSize = sizeof(pStreamIn->deviceID);
+                UInt32 uResp;
+                err = AudioObjectGetPropertyData(kAudioObjectSystemObject, pProperty, 0, NULL, &uSize, &uResp);
+
+                if (err == noErr)
+                {
+                    if (pStreamIn->deviceID != uResp)
+                    {
+                        LogRel(("CoreAudio: Default device for recording has changed\n"));
+
+                        /* We move the reinitialization to the next input event.
+                         * This make sure this thread isn't blocked and the
+                         * reinitialization is done when necessary only. */
+                        ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
+                    }
+                }
+                break;
+            }
+
+            case kAudioHardwarePropertyDefaultOutputDevice:
+            {
+                PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
+                AssertPtr(pStreamOut);
+
+                /* This listener is called on every change of the hardware
+                 * device. So check if the default device has really changed. */
+                AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice,
+                                                       kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+
+                UInt32 uSize = sizeof(pStreamOut->deviceID);
+                UInt32 uResp;
+                err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &uResp);
+
+                if (err == noErr)
+                {
+                    if (pStreamOut->deviceID != uResp)
+                    {
+                        LogRel(("CoreAudio: Default device for playback has changed\n"));
+
+                        /* We move the reinitialization to the next input event.
+                         * This make sure this thread isn't blocked and the
+                         * reinitialization is done when necessary only. */
+                        ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
+                    }
+                }
+                break;
+            }
+
+            default:
+                break;
+        }
+    }
+
+    int rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
+    AssertRC(rc2);
+    rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
+    AssertRC(rc2);
+
+    /** @todo Implement callback notification here to let the audio connector / device emulation
+     *        know that something has changed. */
+
+    return noErr;
+}
+
+/**
+ * Thread for a Core Audio stream's audio queue handling.
+ * This thread is required per audio queue to pump data to/from the Core Audio stream and
+ * handling its callbacks.
+ *
+ * @returns IPRT status code.
+ * @param   hThreadSelf         Thread handle.
+ * @param   pvUser              User argument.
+ */
+static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser)
+{
+    NOREF(hThreadSelf);
+
+    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
+    AssertPtr(pCAStream);
+
+    LogFunc(("Starting pCAStream=%p\n", pCAStream));
+
+    /*
+     * Create audio queue.
+     */
+    OSStatus err;
+    if (pCAStream->enmDir == PDMAUDIODIR_IN)
+        err = AudioQueueNewInput(&pCAStream->asbdStream, coreAudioInputQueueCb, pCAStream /* pvData */,
+                                 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
+    else
+        err = AudioQueueNewOutput(&pCAStream->asbdStream, coreAudioOutputQueueCb, pCAStream /* pvData */,
+                                  CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
+
+    if (err != noErr)
+        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
+
+    /*
+     * Assign device to queue.
+     */
+    UInt32 uSize = sizeof(pCAStream->UUID);
+    err = AudioQueueSetProperty(pCAStream->audioQueue, kAudioQueueProperty_CurrentDevice, &pCAStream->UUID, uSize);
+    if (err != noErr)
+        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
+
+    const size_t cbBufSize = _4K; /** @todo Make this configurable! */
+
+    /*
+     * Allocate audio buffers.
+     */
+    for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
+    {
+        err = AudioQueueAllocateBuffer(pCAStream->audioQueue, cbBufSize, &pCAStream->audioBuffer[i]);
+        if (err != noErr)
+            break;
+    }
+
+    if (err != noErr)
+        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
+
+    /* Signal the main thread before entering the main loop. */
+    RTThreadUserSignal(RTThreadSelf());
+
+    /*
+     * Enter the main loop.
+     */
+    const bool fIn = pCAStream->enmDir == PDMAUDIODIR_IN;
+
+    while (!ASMAtomicReadBool(&pCAStream->fShutdown))
+    {
+        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
+    }
+
+    /*
+     * Cleanup.
+     */
+    if (fIn)
+    {
+        AudioQueueStop(pCAStream->audioQueue, 1);
+    }
+    else
+    {
+        AudioQueueStop(pCAStream->audioQueue, 0);
+    }
+
+    for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
+    {
+        if (pCAStream->audioBuffer[i])
+            AudioQueueFreeBuffer(pCAStream->audioQueue, pCAStream->audioBuffer[i]);
+    }
+
+    AudioQueueDispose(pCAStream->audioQueue, 1);
+
+    LogFunc(("Ended pCAStream=%p\n", pCAStream));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Processes input data of an audio queue buffer and stores it into a Core Audio stream.
+ *
+ * @returns IPRT status code.
+ * @param   pCAStream           Core Audio stream to store input data into.
+ * @param   audioBuffer         Audio buffer to process input data from.
+ */
+int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
+{
+    PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
+    AssertPtr(pCircBuf);
+
+    UInt8 *pvSrc = (UInt8 *)audioBuffer->mAudioData;
+    UInt8 *pvDst = NULL;
+
+    size_t cbWritten = 0;
+
+    size_t cbToWrite = audioBuffer->mAudioDataByteSize;
+    size_t cbLeft    = cbToWrite;
+
+    while (cbLeft)
+    {
+        /* Try to acquire the necessary block from the ring buffer. */
+        RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, (void **)&pvDst, &cbToWrite);
+
+        if (!cbToWrite)
+            break;
+
+        /* Copy the data from our ring buffer to the core audio buffer. */
+        memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite);
+
+        /* Release the read buffer, so it could be used for new data. */
+        RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);
+
+        cbWritten += cbToWrite;
+
+        Assert(cbLeft >= cbToWrite);
+        cbLeft -= cbToWrite;
+    }
+
+    Log3Func(("pCAStream=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n",
+              pCAStream, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten));
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Input audio queue callback. Called whenever input data from the audio queue becomes available.
+ *
+ * @param   pvUser              User argument.
+ * @param   audioQueue          Audio queue to process input data from.
+ * @param   audioBuffer         Audio buffer to process input data from. Must be part of audio queue.
+ * @param   pAudioTS            Audio timestamp.
+ * @param   cPacketDesc         Number of packet descriptors.
+ * @param   paPacketDesc        Array of packet descriptors.
+ */
+static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer,
+                                                const AudioTimeStamp *pAudioTS,
+                                                UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc)
+{
+    NOREF(pAudioTS);
+    NOREF(cPacketDesc);
+    NOREF(paPacketDesc);
+
+    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
+    AssertPtr(pCAStream);
+
+    int rc = RTCritSectEnter(&pCAStream->CritSect);
+    AssertRC(rc);
+
+    rc = coreAudioInputQueueProcBuffer(pCAStream, audioBuffer);
+    if (RT_SUCCESS(rc))
+        AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
+
+    rc = RTCritSectLeave(&pCAStream->CritSect);
+    AssertRC(rc);
+}
+
+/**
+ * Processes output data of a Core Audio stream into an audio queue buffer.
+ *
+ * @returns IPRT status code.
+ * @param   pCAStream           Core Audio stream to process output data for.
+ * @param   audioBuffer         Audio buffer to store data into.
+ */
+int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
+{
+    PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
+    AssertPtr(pCircBuf);
+
+    size_t cbRead = 0;
+
+    UInt8 *pvSrc = NULL;
+    UInt8 *pvDst = (UInt8 *)audioBuffer->mAudioData;
+
+    size_t cbToRead = RT_MIN(RTCircBufUsed(pCircBuf), audioBuffer->mAudioDataBytesCapacity);
+    size_t cbLeft   = cbToRead;
+
+    while (cbLeft)
+    {
+        /* Try to acquire the necessary block from the ring buffer. */
+        RTCircBufAcquireReadBlock(pCircBuf, cbLeft, (void **)&pvSrc, &cbToRead);
+
+        if (cbToRead)
+        {
+            /* Copy the data from our ring buffer to the core audio buffer. */
+            memcpy((UInt8 *)pvDst + cbRead, pvSrc, cbToRead);
+        }
+
+        /* Release the read buffer, so it could be used for new data. */
+        RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
+
+        if (!cbToRead)
+            break;
+
+        /* Move offset. */
+        cbRead += cbToRead;
+        Assert(cbRead <= audioBuffer->mAudioDataBytesCapacity);
+
+        Assert(cbToRead <= cbLeft);
+        cbLeft -= cbToRead;
+    }
+
+    audioBuffer->mAudioDataByteSize = cbRead;
+
+    if (audioBuffer->mAudioDataByteSize < audioBuffer->mAudioDataBytesCapacity)
+    {
+        RT_BZERO((UInt8 *)audioBuffer->mAudioData + audioBuffer->mAudioDataByteSize,
+                 audioBuffer->mAudioDataBytesCapacity - audioBuffer->mAudioDataByteSize);
+
+        audioBuffer->mAudioDataByteSize = audioBuffer->mAudioDataBytesCapacity;
+    }
+
+    Log3Func(("pCAStream=%p, cbCapacity=%RU32, cbRead=%zu\n",
+              pCAStream, audioBuffer->mAudioDataBytesCapacity, cbRead));
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Output audio queue callback. Called whenever an audio queue is ready to process more output data.
+ *
+ * @param   pvUser              User argument.
+ * @param   audioQueue          Audio queue to process output data for.
+ * @param   audioBuffer         Audio buffer to store output data in. Must be part of audio queue.
+ */
+static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer)
+{
+    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
+    AssertPtr(pCAStream);
+
+    int rc = RTCritSectEnter(&pCAStream->CritSect);
+    AssertRC(rc);
+
+    rc = coreAudioOutputQueueProcBuffer(pCAStream, audioBuffer);
+    if (RT_SUCCESS(rc))
+        AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
+
+    rc = RTCritSectLeave(&pCAStream->CritSect);
+    AssertRC(rc);
+}
+
+/**
+ * Invalidates a Core Audio stream's audio queue.
+ *
+ * @returns IPRT status code.
+ * @param   pCAStream           Core Audio stream to invalidate its queue for.
+ */
+static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pCAStream)
+{
+    int rc = VINF_SUCCESS;
+
+    for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
+    {
+        AudioQueueBufferRef pBuf = pCAStream->audioBuffer[i];
+
+        if (pCAStream->enmDir == PDMAUDIODIR_IN)
+        {
+            int rc2 = coreAudioInputQueueProcBuffer(pCAStream, pBuf);
+            if (RT_SUCCESS(rc2))
+            {
+                AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
+            }
+        }
+        else if (pCAStream->enmDir == PDMAUDIODIR_OUT)
+        {
+            int rc2 = coreAudioOutputQueueProcBuffer(pCAStream, pBuf);
+            if (   RT_SUCCESS(rc2)
+                && pBuf->mAudioDataByteSize)
+            {
+                AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
+            }
+
+            if (RT_SUCCESS(rc))
+                rc = rc2;
+        }
+        else
+            AssertFailed();
+    }
+
+    return rc;
+}
+
+/**
+ * Initializes a Core Audio stream's audio queue.
+ *
+ * @returns IPRT status code.
+ * @param   pCAStream           Core Audio stream to initialize audio queue for.
+ * @param   fIn                 Whether this is an input or output queue.
+ * @param   pCfgReq             Requested stream configuration.
+ * @param   pCfgAcq             Acquired stream configuration on success.
+ */
+static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, bool fIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+{
+    RT_NOREF(pCfgAcq);
+    LogFunc(("pCAStream=%p, pCfgReq=%p, pCfgAcq=%p\n", pCAStream, pCfgReq, pCfgAcq));
+
+    AudioDeviceID deviceID = kAudioDeviceUnknown;
+
+    /* Fetch the default audio device currently in use. */
+    AudioObjectPropertyAddress propAdrDefaultDev = {   fIn
+                                                     ? kAudioHardwarePropertyDefaultInputDevice
+                                                     : kAudioHardwarePropertyDefaultOutputDevice,
+                                                     kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+    UInt32 uSize = sizeof(deviceID);
+    OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdrDefaultDev, 0, NULL, &uSize, &deviceID);
+    if (err != noErr)
+    {
+        LogRel(("CoreAudio: Unable to determine default %s device (%RI32)\n",
+                fIn ? "capturing" : "playback", err));
+        return VERR_NOT_FOUND;
+    }
+
+    /* Get the device UUID. */
+    AudioObjectPropertyAddress propAdrDevUUID = { kAudioDevicePropertyDeviceUID,
+                                                  fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+                                                  kAudioObjectPropertyElementMaster };
+    uSize = sizeof(pCAStream->UUID);
+    err = AudioObjectGetPropertyData(deviceID, &propAdrDevUUID, 0, NULL, &uSize, &pCAStream->UUID);
+    if (err != noErr)
+    {
+        LogRel(("CoreAudio: Failed to retrieve device UUID for device %RU32 (%RI32)\n", deviceID, err));
+        return VERR_NOT_FOUND;
+    }
+
+    /* Create the recording device's out format based on our required audio settings. */
+    int rc = drvHostCoreAudioStreamCfgToASBD(pCfgReq, &pCAStream->asbdStream);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("CoreAudio: Failed to convert requested %s format to native format (%Rrc)\n",
+                fIn ? "input" : "output", rc));
+        return rc;
+    }
+
+    pCAStream->enmDir = fIn ? PDMAUDIODIR_IN : PDMAUDIODIR_OUT;
+
+    /* Assign device ID. */
+    if (fIn)
+    {
+        AssertPtr(pCAStream->pIn);
+        pCAStream->pIn->deviceID = deviceID;
+    }
+    else
+    {
+        AssertPtr(pCAStream->pOut);
+        pCAStream->pOut->deviceID = deviceID;
+    }
+
+    drvHostCoreAudioPrintASBD(  fIn
+                              ? "Capturing queue format"
+                              : "Playback queue format", &pCAStream->asbdStream);
+
+    rc = RTCircBufCreate(&pCAStream->pCircBuf, 8096 << 1 /*pHstStrmIn->Props.cShift*/); /** @todo FIX THIS !!! */
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Start the thread.
+     */
+    rc = RTThreadCreate(&pCAStream->hThread, coreAudioQueueThread,
+                        pCAStream /* pvUser */, 0 /* Default stack size */,
+                        RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "CAQUEUE");
+    if (RT_SUCCESS(rc))
+        rc = RTThreadUserWait(pCAStream->hThread, 10 * 1000 /* 10s timeout */);
+
+    LogFunc(("Returning %Rrc\n", rc));
+    return rc;
+}
+
+/**
+ * Unitializes a Core Audio stream's audio queue.
+ *
+ * @returns IPRT status code.
+ * @param   pCAStream           Core Audio stream to unitialize audio queue for.
+ */
+static int coreAudioStreamUninitQueue(PCOREAUDIOSTREAM pCAStream)
+{
+    LogFunc(("pCAStream=%p\n", pCAStream));
+
+    int rc;
+
+    if (pCAStream->hThread != NIL_RTTHREAD)
+    {
+        LogFunc(("Waiting for thread ...\n"));
+
+        ASMAtomicXchgBool(&pCAStream->fShutdown, true);
+
+        int rcThread;
+        rc = RTThreadWait(pCAStream->hThread, 30 * 1000, &rcThread);
+        if (RT_FAILURE(rc))
+            return rc;
+
+        NOREF(rcThread);
+        LogFunc(("Thread stopped with %Rrc\n", rcThread));
+
+        pCAStream->hThread = NIL_RTTHREAD;
+    }
+
+    if (pCAStream->pCircBuf)
+    {
+        RTCircBufDestroy(pCAStream->pCircBuf);
+        pCAStream->pCircBuf = NULL;
+    }
+
+    LogFunc(("Returning\n"));
+    return VINF_SUCCESS;
+}
+
+#if 0 // unused
+/**
+ * Unitializes a Core Audio stream.
+ *
+ * @returns IPRT status code.
+ * @param   pCAStream           Core Audio stream to uninitialize.
+ */
+static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)
+{
+    LogFunc(("pCAStream=%p\n", pCAStream));
+
+    int rc = coreAudioStreamUninitQueue(pCAStream);
+    return rc;
+}
+#endif
+
+static int drvHostCoreAudioReinitInput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    int rc = drvHostCoreAudioFiniIn(pInterface, pHstStrmIn);
+    if (RT_SUCCESS(rc))
+    {
+        PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
+
+        PDMAUDIOSTREAMCFG CfgAcq;
+        rc = drvHostCoreAudioASBDToStreamCfg(&pStreamIn->cbCtx.pStream->asbdStream, &CfgAcq);
+        if (RT_SUCCESS(rc))
+        {
+            rc = coreAudioStreamInitQueue(pStreamIn->cbCtx.pStream, true /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
+            if (RT_SUCCESS(rc))
+                rc = drvHostCoreAudioControlIn(pInterface, pHstStrmIn, PDMAUDIOSTREAMCMD_ENABLE);
+
+            if (RT_FAILURE(rc))
+            {
+                int rc2 = drvHostCoreAudioFiniIn(pInterface, pHstStrmIn);
+                AssertRC(rc2);
+            }
+        }
+    }
+
+    if (RT_FAILURE(rc))
+        LogRel(("CoreAudio: Unable to re-init input stream: %Rrc\n", rc));
+
+    return rc;
+}
+
+static int drvHostCoreAudioReinitOutput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    int rc = drvHostCoreAudioFiniOut(pInterface, pHstStrmOut);
+    if (RT_SUCCESS(rc))
+    {
+        PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
+        PDMAUDIOSTREAMCFG CfgAcq;
+        rc = drvHostCoreAudioASBDToStreamCfg(&pStreamOut->cbCtx.pStream->asbdStream, &CfgAcq);
+        if (RT_SUCCESS(rc))
+        {
+            rc = coreAudioStreamInitQueue(pStreamOut->cbCtx.pStream, false /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
+            if (RT_SUCCESS(rc))
+                rc = drvHostCoreAudioControlOut(pInterface, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
+
+            if (RT_FAILURE(rc))
+            {
+                int rc2 = drvHostCoreAudioFiniOut(pInterface, pHstStrmOut);
+                AssertRC(rc2);
+            }
+        }
+    }
+
+    if (RT_FAILURE(rc))
+        LogRel(("CoreAudio: Unable to re-init output stream: %Rrc\n", rc));
+
+    return rc;
+}
+
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+/* Callback to convert audio input data from one format to another. */
+static DECLCALLBACK(OSStatus) drvHostCoreAudioConverterCb(AudioConverterRef              inAudioConverter,
+                                                          UInt32                        *ioNumberDataPackets,
+                                                          AudioBufferList               *ioData,
+                                                          AudioStreamPacketDescription **ppASPD,
+                                                          void                          *pvUser)
+{
+    RT_NOREF(inAudioConverter);
+    AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);
+    AssertPtrReturn(ioData,              caConverterEOFDErr);
+
+    PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser;
+    AssertPtr(pConvCbCtx);
+
+    /* Initialize values. */
+    ioData->mBuffers[0].mNumberChannels = 0;
+    ioData->mBuffers[0].mDataByteSize   = 0;
+    ioData->mBuffers[0].mData           = NULL;
+
+    if (ppASPD)
+    {
+        Log3Func(("Handling packet description not implemented\n"));
+    }
+    else
+    {
+        /** @todo Check converter ID? */
+
+        /** @todo Handled non-interleaved data by going through the full buffer list,
+         *        not only through the first buffer like we do now. */
+        Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
+
+        UInt32 cNumberDataPackets = *ioNumberDataPackets;
+        Assert(pConvCbCtx->uPacketIdx + cNumberDataPackets <= pConvCbCtx->uPacketCnt);
+
+        if (cNumberDataPackets)
+        {
+            AssertPtr(pConvCbCtx->pBufLstSrc);
+            Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
+
+            AudioStreamBasicDescription *pSrcASBD = &pConvCbCtx->asbdSrc;
+            AudioBuffer                 *pSrcBuf  = &pConvCbCtx->pBufLstSrc->mBuffers[0];
+
+            size_t cbOff   = pConvCbCtx->uPacketIdx * pSrcASBD->mBytesPerPacket;
+
+            cNumberDataPackets = RT_MIN((pSrcBuf->mDataByteSize - cbOff) / pSrcASBD->mBytesPerPacket,
+                                        cNumberDataPackets);
+
+            void  *pvAvail = (uint8_t *)pSrcBuf->mData + cbOff;
+            size_t cbAvail = RT_MIN(pSrcBuf->mDataByteSize - cbOff, cNumberDataPackets * pSrcASBD->mBytesPerPacket);
+
+            Log3Func(("cNumberDataPackets=%RU32, cbOff=%zu, cbAvail=%zu\n", cNumberDataPackets, cbOff, cbAvail));
+
+            /* Set input data for the converter to use.
+             * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
+            ioData->mNumberBuffers = 1;
+
+            ioData->mBuffers[0].mNumberChannels = pSrcBuf->mNumberChannels;
+            ioData->mBuffers[0].mDataByteSize   = cbAvail;
+            ioData->mBuffers[0].mData           = pvAvail;
+
+#ifdef DEBUG_DUMP_PCM_DATA
+            RTFILE fh;
+            int rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-converter-cb-input.pcm",
+                                RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+            if (RT_SUCCESS(rc))
+            {
+                RTFileWrite(fh, pvAvail, cbAvail, NULL);
+                RTFileClose(fh);
+            }
+            else
+                AssertFailed();
+#endif
+            pConvCbCtx->uPacketIdx += cNumberDataPackets;
+            Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
+
+            *ioNumberDataPackets = cNumberDataPackets;
+        }
+    }
+
+    Log3Func(("%RU32 / %RU32 -> ioNumberDataPackets=%RU32\n",
+              pConvCbCtx->uPacketIdx, pConvCbCtx->uPacketCnt, *ioNumberDataPackets));
+
+    return noErr;
+}
+#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
+
+
+/* Callback for getting notified when some of the properties of an audio device have changed. */
+static DECLCALLBACK(OSStatus) drvHostCoreAudioDevPropChgCb(AudioObjectID                     propertyID,
+                                                           UInt32                            cAddresses,
+                                                           const AudioObjectPropertyAddress  properties[],
+                                                           void                             *pvUser)
+{
+    RT_NOREF(cAddresses, properties);
+    PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
+    AssertPtr(pCbCtx);
+    AssertPtr(pCbCtx->pStream);
+
+    LogFlowFunc(("propertyID=%u, nAddresses=%u, pCbCtx=%p\n", propertyID, cAddresses, pCbCtx));
+
+    if (pCbCtx->pStream->enmDir == PDMAUDIODIR_IN)
+    {
+        PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
+        AssertPtr(pStreamIn);
+
+        switch (propertyID)
+        {
+#ifdef DEBUG
+           case kAudioDeviceProcessorOverload:
+            {
+                LogFunc(("Processor overload detected!\n"));
+                break;
+            }
+#endif /* DEBUG */
+            case kAudioDevicePropertyNominalSampleRate:
+            {
+                LogRel2(("CoreAudio: Recording sample rate changed\n"));
+
+                /* We move the reinitialization to the next input event.
+                 * This make sure this thread isn't blocked and the
+                 * reinitialization is done when necessary only. */
+                ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
+                break;
+            }
+
+            default:
+                break;
+        }
+    }
+    else
+    {
+        PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
+        AssertPtr(pStreamOut);
+
+        switch (propertyID)
+        {
+            case kAudioDevicePropertyNominalSampleRate:
+            {
+                LogRel2(("CoreAudio: Playback sample rate changed\n"));
+
+                /* We move the reinitialization to the next input event.
+                 * This make sure this thread isn't blocked and the
+                 * reinitialization is done when necessary only. */
+                ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
+                break;
+            }
+
+            default:
+                break;
+        }
+    }
+
+    return noErr;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioInit(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   uint32_t *pcSamplesCaptured)
+{
+    PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
+
+    /* Check if the audio device should be reinitialized. If so do it. */
+    if (ASMAtomicReadU32(&pStreamIn->status) == CA_STATUS_REINIT)
+        drvHostCoreAudioReinitInput(pInterface, &pStreamIn->streamIn);
+
+    if (ASMAtomicReadU32(&pStreamIn->status) != CA_STATUS_INIT)
+    {
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = 0;
+        return VINF_SUCCESS;
+    }
+
+    PRTCIRCBUF pCircBuf = NULL;
+    pCircBuf = pStreamIn->cbCtx.pStream->pCircBuf;
+    AssertPtr(pCircBuf);
+
+    int rc = VINF_SUCCESS;
+    uint32_t cbWrittenTotal = 0;
+
+    do
+    {
+        size_t cbBuf     = AudioMixBufSizeBytes(&pHstStrmIn->MixBuf);
+        size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(pCircBuf));
+
+        uint32_t cWritten, cbWritten;
+        uint8_t *puBuf;
+        size_t   cbToRead;
+
+        Log3Func(("cbBuf=%zu, cbToWrite=%zu/%zu\n", cbBuf, cbToWrite, RTCircBufSize(pCircBuf)));
+
+        while (cbToWrite)
+        {
+            /* Try to acquire the necessary block from the ring buffer. */
+            RTCircBufAcquireReadBlock(pCircBuf, cbToWrite, (void **)&puBuf, &cbToRead);
+
+            if (cbToRead)
+            {
+#ifdef DEBUG_DUMP_PCM_DATA
+                RTFILE fh;
+                rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-capture.pcm",
+                                RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+                if (RT_SUCCESS(rc))
+                {
+                    RTFileWrite(fh, puBuf + cbWrittenTotal, cbToRead, NULL);
+                    RTFileClose(fh);
+                }
+                else
+                    AssertFailed();
+#endif
+                rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, puBuf, cbToRead, &cWritten);
+            }
+
+            /* Release the read buffer, so it could be used for new data. */
+            RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
+
+            if (   RT_FAILURE(rc)
+                || !cWritten)
+            {
+                break;
+            }
+
+            cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
+
+            Assert(cbToWrite >= cbWritten);
+            cbToWrite      -= cbWritten;
+            cbWrittenTotal += cbWritten;
+        }
+
+        Log3Func(("cbToWrite=%zu, cbToRead=%zu, cbWrittenTotal=%RU32, rc=%Rrc\n", cbToWrite, cbToRead, cbWrittenTotal, rc));
+    }
+    while (0);
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cCaptured     = 0;
+        uint32_t cWrittenTotal = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbWrittenTotal);
+        if (cWrittenTotal)
+            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal, &cCaptured);
+
+        Log3Func(("cWrittenTotal=%RU32 (%RU32 bytes), cCaptured=%RU32, rc=%Rrc\n", cWrittenTotal, cbWrittenTotal, cCaptured, rc));
+
+        if (cCaptured)
+            LogFlowFunc(("%RU32 samples captured\n", cCaptured));
+
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cCaptured;
+    }
+
+    if (RT_FAILURE(rc))
+        LogFunc(("Failed with rc=%Rrc\n", rc));
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                 uint32_t *pcSamplesPlayed)
+{
+    PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
+    int rc = VINF_SUCCESS;
+
+    /* Check if the audio device should be reinitialized. If so do it. */
+    if (ASMAtomicReadU32(&pStreamOut->status) == CA_STATUS_REINIT)
+    {
+        rc = drvHostCoreAudioReinitOutput(pInterface, &pStreamOut->streamOut);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+    if (!cLive) /* Not samples to play? Bail out. */
+    {
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = 0;
+        return VINF_SUCCESS;
+    }
+
+    PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+    AssertPtr(pCAStream);
+
+    PRTCIRCBUF pCircBuf = NULL;
+    pCircBuf = pCAStream->pCircBuf;
+    AssertPtr(pCircBuf);
+
+    size_t cbLive  = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cLive);
+
+    uint32_t cbReadTotal = 0;
+
+    size_t cbToRead = RT_MIN(cbLive, RTCircBufFree(pCircBuf));
+    Log3Func(("cbLive=%zu, cbToRead=%zu\n", cbLive, cbToRead));
+
+    uint8_t *pvChunk;
+    size_t   cbChunk;
+
+    while (cbToRead)
+    {
+        uint32_t cRead, cbRead;
+
+        /* Try to acquire the necessary space from the ring buffer. */
+        RTCircBufAcquireWriteBlock(pCircBuf, cbToRead, (void **)&pvChunk, &cbChunk);
+        if (!cbChunk)
+        {
+            RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
+            break;
+        }
+
+        Assert(cbChunk <= cbToRead);
+
+        rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pvChunk, cbChunk, &cRead);
+
+        cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
+
+        /* Release the ring buffer, so the read thread could start reading this data. */
+        RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
+
+        if (RT_FAILURE(rc))
+            break;
+
+        Assert(cbToRead >= cbRead);
+        cbToRead -= cbRead;
+        cbReadTotal += cbRead;
+    }
+
+    if (    RT_SUCCESS(rc)
+        &&  pCAStream->fRun
+        && !pCAStream->fIsRunning)
+    {
+        rc = coreAudioStreamInvalidateQueue(pCAStream);
+        if (RT_SUCCESS(rc))
+        {
+            AudioQueueStart(pCAStream->audioQueue, NULL);
+            pCAStream->fRun       = false;
+            pCAStream->fIsRunning = true;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
+        if (cReadTotal)
+            AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
+
+        Log3Func(("cReadTotal=%RU32 (%RU32 bytes)\n", cReadTotal, cbReadTotal));
+
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = cReadTotal;
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                    PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    RT_NOREF(pInterface);
+    PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
+    LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
+
+    uint32_t uStatus = ASMAtomicReadU32(&pStreamOut->status);
+    if (!(   uStatus == CA_STATUS_INIT
+          || uStatus == CA_STATUS_REINIT))
+    {
+        return VINF_SUCCESS;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+    AssertPtr(pCAStream);
+
+    OSStatus err; RT_NOREF(err);
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            LogFunc(("Queue enable\n"));
+            if (pCAStream->enmDir == PDMAUDIODIR_IN)
+            {
+                rc = coreAudioStreamInvalidateQueue(pCAStream);
+                if (RT_SUCCESS(rc))
+                {
+                    /* Start the audio queue immediately. */
+                    AudioQueueStart(pCAStream->audioQueue, NULL);
+                }
+            }
+            if (pCAStream->enmDir == PDMAUDIODIR_OUT)
+            {
+                /* Touch the run flag to start the audio queue as soon as
+                 * we have anough data to actually play something. */
+                ASMAtomicXchgBool(&pCAStream->fRun, true);
+            }
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        {
+            LogFunc(("Queue disable\n"));
+            AudioQueueStop(pCAStream->audioQueue, 1 /* Immediately */);
+            ASMAtomicXchgBool(&pCAStream->fRun,       false);
+            ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            LogFunc(("Queue pause\n"));
+            AudioQueuePause(pCAStream->audioQueue);
+            ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    RT_NOREF(pInterface);
+    PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
+
+    LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
+
+    uint32_t uStatus = ASMAtomicReadU32(&pStreamIn->status);
+    if (!(   uStatus == CA_STATUS_INIT
+          || uStatus == CA_STATUS_REINIT))
+    {
+        return VINF_SUCCESS;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
+    AssertPtr(pCAStream);
+
+    OSStatus err; RT_NOREF(err);
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            LogFunc(("Queue enable\n"));
+            if (pCAStream->enmDir == PDMAUDIODIR_IN)
+            {
+                rc = coreAudioStreamInvalidateQueue(pCAStream);
+                if (RT_SUCCESS(rc))
+                {
+                    /* Start the audio queue immediately. */
+                    AudioQueueStart(pCAStream->audioQueue, NULL);
+                }
+            }
+            if (pCAStream->enmDir == PDMAUDIODIR_OUT)
+            {
+                /* Touch the run flag to start the audio queue as soon as
+                 * we have anough data to actually play something. */
+                ASMAtomicXchgBool(&pCAStream->fRun, true);
+            }
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        {
+            LogFunc(("Queue disable\n"));
+            AudioQueueStop(pCAStream->audioQueue, 1 /* Immediately */);
+            ASMAtomicXchgBool(&pCAStream->fRun,       false);
+            ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
+            break;
+        }
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            LogFunc(("Queue pause\n"));
+            AudioQueuePause(pCAStream->audioQueue);
+            ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN) pHstStrmIn;
+
+    LogFlowFuncEnter();
+
+    uint32_t status = ASMAtomicReadU32(&pStreamIn->status);
+    if (!(   status == CA_STATUS_INIT
+          || status == CA_STATUS_REINIT))
+    {
+        return VINF_SUCCESS;
+    }
+
+    OSStatus err = noErr;
+
+    int rc = drvHostCoreAudioControlIn(pInterface, &pStreamIn->streamIn, PDMAUDIOSTREAMCMD_DISABLE);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Unregister recording device callbacks.
+         */
+        AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
+                                               kAudioObjectPropertyElementMaster };
+#ifdef DEBUG
+        err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
+                                                drvHostCoreAudioDevPropChgCb, &pStreamIn->cbCtx /* pvUser */);
+        if (   err != noErr
+            && err != kAudioHardwareBadObjectError)
+        {
+            LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
+        }
+#endif /* DEBUG */
+
+        propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
+        err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
+                                                drvHostCoreAudioDevPropChgCb, &pStreamIn->cbCtx /* pvUser */);
+        if (   err != noErr
+            && err != kAudioHardwareBadObjectError)
+        {
+            LogRel(("CoreAudio: Failed to remove the recording sample rate changed listener (%RI32)\n", err));
+        }
+
+        if (pStreamIn->fDefDevChgListReg)
+        {
+            propAdr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+            err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
+                                                    drvHostCoreAudioDefaultDeviceChangedCb, pStreamIn);
+            if (   err != noErr
+                && err != kAudioHardwareBadObjectError)
+            {
+                LogRel(("CoreAudio: Failed to remove the default recording device changed listener (%RI32)\n", err));
+            }
+
+            pStreamIn->fDefDevChgListReg = false;
+        }
+
+        if (pStreamIn->fDevStateChgListReg)
+        {
+            Assert(pStreamIn->deviceID != kAudioDeviceUnknown);
+
+            AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+                                                    kAudioObjectPropertyElementMaster };
+            err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr2,
+                                                    drvHostCoreAudioDeviceStateChangedCb, &pStreamIn->cbCtx);
+            if (   err != noErr
+                && err != kAudioHardwareBadObjectError)
+            {
+                LogRel(("CoreAudio: Failed to remove the recording device state changed listener (%RI32)\n", err));
+            }
+
+            pStreamIn->fDevStateChgListReg = false;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
+
+            rc = coreAudioStreamUninitQueue(pCAStream);
+            if (RT_FAILURE(rc))
+                return rc;
+
+            if (RTCritSectIsInitialized(&pCAStream->CritSect))
+                RTCritSectDelete(&pCAStream->CritSect);
+        }
+
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+        if (pStreamIn->ConverterRef)
+        {
+            AudioConverterDispose(pStreamIn->ConverterRef);
+            pStreamIn->ConverterRef = NULL;
+        }
+#endif
+        err = AudioUnitUninitialize(pStreamIn->audioUnit);
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+        if (err == noErr)
+            err = CloseComponent(pStreamIn->audioUnit);
+#pragma clang diagnostic pop
+
+        if (   err != noErr
+            && err != kAudioHardwareBadObjectError)
+        {
+            LogRel(("CoreAudio: Failed to uninit the recording device (%RI32)\n", err));
+        }
+
+        pStreamIn->deviceID      = kAudioDeviceUnknown;
+        pStreamIn->audioUnit     = NULL;
+        pStreamIn->sampleRatio   = 1;
+
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+        drvHostCoreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
+#endif
+        if (pStreamIn->pCircBuf)
+        {
+            RTCircBufDestroy(pStreamIn->pCircBuf);
+            pStreamIn->pCircBuf = NULL;
+        }
+
+        ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
+    }
+    else
+    {
+        LogRel(("CoreAudio: Failed to stop recording on uninit (%RI32)\n", err));
+        rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
+    LogFlowFuncEnter();
+
+    uint32_t status = ASMAtomicReadU32(&pStreamOut->status);
+    if (!(   status == CA_STATUS_INIT
+          || status == CA_STATUS_REINIT))
+    {
+        return VINF_SUCCESS;
+    }
+
+    int rc = drvHostCoreAudioControlOut(pInterface, &pStreamOut->streamOut, PDMAUDIOSTREAMCMD_DISABLE);
+    if (RT_SUCCESS(rc))
+    {
+        OSStatus err;
+
+        /*
+         * Unregister playback device callbacks.
+         */
+        AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
+                                               kAudioObjectPropertyElementMaster };
+#ifdef DEBUG
+        err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
+                                                drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
+        if (   err != noErr
+            && err != kAudioHardwareBadObjectError)
+        {
+            LogRel(("CoreAudio: Failed to remove the playback processor overload listener (%RI32)\n", err));
+        }
+#endif /* DEBUG */
+
+        propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
+        err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
+                                                drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
+        if (   err != noErr
+            && err != kAudioHardwareBadObjectError)
+        {
+            LogRel(("CoreAudio: Failed to remove the playback sample rate changed listener (%RI32)\n", err));
+        }
+
+        if (pStreamOut->fDefDevChgListReg)
+        {
+            propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+            propAdr.mScope    = kAudioObjectPropertyScopeGlobal;
+            propAdr.mElement  = kAudioObjectPropertyElementMaster;
+            err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
+                                                    drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
+            if (   err != noErr
+                && err != kAudioHardwareBadObjectError)
+            {
+                LogRel(("CoreAudio: Failed to remove the default playback device changed listener (%RI32)\n", err));
+            }
+
+            pStreamOut->fDefDevChgListReg = false;
+        }
+
+        if (pStreamOut->fDevStateChgListReg)
+        {
+            Assert(pStreamOut->deviceID != kAudioDeviceUnknown);
+
+            AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+                                                    kAudioObjectPropertyElementMaster };
+            err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr2,
+                                                    drvHostCoreAudioDeviceStateChangedCb, &pStreamOut->cbCtx);
+            if (   err != noErr
+                && err != kAudioHardwareBadObjectError)
+            {
+                LogRel(("CoreAudio: Failed to remove the playback device state changed listener (%RI32)\n", err));
+            }
+
+            pStreamOut->fDevStateChgListReg = false;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+
+            rc = coreAudioStreamUninitQueue(pCAStream);
+            if (RT_FAILURE(rc))
+                return rc;
+
+            if (RTCritSectIsInitialized(&pCAStream->CritSect))
+                RTCritSectDelete(&pCAStream->CritSect);
+        }
+        err = AudioUnitUninitialize(pStreamOut->audioUnit);
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+        if (err == noErr)
+            err = CloseComponent(pStreamOut->audioUnit);
+#pragma clang diagnostic pop
+
+        if (   err != noErr
+            && err != kAudioHardwareBadObjectError)
+        {
+            LogRel(("CoreAudio: Failed to uninit the playback device (%RI32)\n", err));
+        }
+
+        pStreamOut->deviceID  = kAudioDeviceUnknown;
+        pStreamOut->audioUnit = NULL;
+        if (pStreamOut->pCircBuf)
+        {
+            RTCircBufDestroy(pStreamOut->pCircBuf);
+            pStreamOut->pCircBuf = NULL;
+        }
+
+        ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
+    }
+    else
+        LogRel(("CoreAudio: Failed to stop playback on uninit, rc=%Rrc\n", rc));
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioInitIn(PPDMIHOSTAUDIO pInterface,
+                                                PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
+{
+    RT_NOREF(enmRecSource);
+    PPDMDRVINS        pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTCOREAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
+
+    PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
+
+    LogFlowFunc(("enmRecSource=%RU32\n", enmRecSource));
+
+    pStreamIn->deviceID            = kAudioDeviceUnknown;
+    pStreamIn->audioUnit           = NULL;
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+    pStreamIn->ConverterRef        = NULL;
+#endif
+    pStreamIn->sampleRatio         = 1;
+    pStreamIn->pCircBuf            = NULL;
+    pStreamIn->status              = CA_STATUS_UNINIT;
+    pStreamIn->fDefDevChgListReg   = false;
+    pStreamIn->fDevStateChgListReg = false;
+
+    /* Set attributes. */
+    pStreamIn->Stream.enmDir = PDMAUDIODIR_IN;
+    pStreamIn->Stream.pIn    = pStreamIn;
+
+    /* Set callback context. */
+    pStreamIn->cbCtx.pThis   = pThis;
+    pStreamIn->cbCtx.pStream = &pStreamIn->Stream;
+
+    int rc;
+
+    PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
+
+    rc = RTCritSectInit(&pCAStream->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    pCAStream->hThread    = NIL_RTTHREAD;
+    pCAStream->fRun       = false;
+    pCAStream->fIsRunning = false;
+    pCAStream->fShutdown  = false;
+
+    bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
+#if 0
+    /* Try to find the audio device set by the user */
+    if (DeviceUID.pszInputDeviceUID)
+    {
+        pStreamIn->deviceID = drvHostCoreAudioDeviceUIDtoID(DeviceUID.pszInputDeviceUID);
+        /* Not fatal */
+        if (pStreamIn->deviceID == kAudioDeviceUnknown)
+            LogRel(("CoreAudio: Unable to find recording device %s. Falling back to the default audio device. \n", DeviceUID.pszInputDeviceUID));
+        else
+            fDeviceByUser = true;
+    }
+#endif
+
+    rc = coreAudioStreamInitQueue(pStreamIn->cbCtx.pStream, true /* fIn */, pCfgReq, pCfgAcq);
+    if (RT_SUCCESS(rc))
+    {
+        *pcSamples = _4K; /** @todo Make this configurable. */
+    }
+    if (RT_SUCCESS(rc))
+    {
+        ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_INIT);
+
+        OSStatus err;
+
+        /* When the devices isn't forced by the user, we want default device change notifications. */
+        if (!fDeviceByUser)
+        {
+            if (!pStreamIn->fDefDevChgListReg)
+            {
+                AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
+                                                       kAudioObjectPropertyElementMaster };
+                err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
+                                                     drvHostCoreAudioDefaultDeviceChangedCb, &pStreamIn->cbCtx);
+                if (   err == noErr
+                    || err == kAudioHardwareIllegalOperationError)
+                {
+                    pStreamIn->fDefDevChgListReg = true;
+                }
+                else
+                    LogRel(("CoreAudio: Failed to add the default recording device changed listener (%RI32)\n", err));
+            }
+        }
+
+        if (   !pStreamIn->fDevStateChgListReg
+            && (pStreamIn->deviceID != kAudioDeviceUnknown))
+        {
+            /* Register callback for being notified if the device stops being alive. */
+            AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+                                                   kAudioObjectPropertyElementMaster };
+            err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr, drvHostCoreAudioDeviceStateChangedCb,
+                                                 &pStreamIn->cbCtx);
+            if (err == noErr)
+            {
+                pStreamIn->fDevStateChgListReg = true;
+            }
+            else
+                LogRel(("CoreAudio: Failed to add the recording device state changed listener (%RI32)\n", err));
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioInitOut(PPDMIHOSTAUDIO pInterface,
+                                                 PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                 uint32_t *pcSamples)
+{
+    PPDMDRVINS        pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTCOREAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
+
+    PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
+    LogFlowFuncEnter();
+
+    pStreamOut->deviceID            = kAudioDeviceUnknown;
+    pStreamOut->audioUnit           = NULL;
+    pStreamOut->pCircBuf            = NULL;
+    pStreamOut->status              = CA_STATUS_UNINIT;
+    pStreamOut->fDefDevChgListReg   = false;
+    pStreamOut->fDevStateChgListReg = false;
+
+    /* Set attributes. */
+    pStreamOut->Stream.enmDir = PDMAUDIODIR_OUT;
+    pStreamOut->Stream.pOut   = pStreamOut;
+
+    /* Set callback context. */
+    pStreamOut->cbCtx.pThis   = pThis;
+    pStreamOut->cbCtx.pStream = &pStreamOut->Stream;
+
+    PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+    
+    int rc = RTCritSectInit(&pCAStream->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    pCAStream->hThread    = NIL_RTTHREAD;
+    pCAStream->fRun       = false;
+    pCAStream->fIsRunning = false;
+    pCAStream->fShutdown  = false;
+
+    bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
+
+#if 0
+    /* Try to find the audio device set by the user. Use
+     * export VBOX_COREAUDIO_OUTPUT_DEVICE_UID=AppleHDAEngineOutput:0
+     * to set it. */
+    if (DeviceUID.pszOutputDeviceUID)
+    {
+        pStreamOut->audioDeviceId = drvHostCoreAudioDeviceUIDtoID(DeviceUID.pszOutputDeviceUID);
+        /* Not fatal */
+        if (pStreamOut->audioDeviceId == kAudioDeviceUnknown)
+            LogRel(("CoreAudio: Unable to find playback device %s. Falling back to the default audio device. \n", DeviceUID.pszOutputDeviceUID));
+        else
+            fDeviceByUser = true;
+    }
+#endif
+
+    rc = coreAudioStreamInitQueue(pStreamOut->cbCtx.pStream, false /* fIn */, pCfgReq, pCfgAcq);
+    if (RT_SUCCESS(rc))
+    {
+        *pcSamples = _4K; /** @todo Make this configurable. */
+    }
+    if (RT_SUCCESS(rc))
+    {
+        ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_INIT);
+
+        OSStatus err;
+
+        /* When the devices isn't forced by the user, we want default device change notifications. */
+        if (!fDeviceByUser)
+        {
+            AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
+                                                   kAudioObjectPropertyElementMaster };
+            err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
+                                                 drvHostCoreAudioDefaultDeviceChangedCb, &pStreamOut->cbCtx);
+            if (err == noErr)
+            {
+                pStreamOut->fDefDevChgListReg = true;
+            }
+            else
+                LogRel(("CoreAudio: Failed to add the default playback device changed listener (%RI32)\n", err));
+        }
+
+        if (   !pStreamOut->fDevStateChgListReg
+            && (pStreamOut->deviceID != kAudioDeviceUnknown))
+        {
+            /* Register callback for being notified if the device stops being alive. */
+            AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+                                                   kAudioObjectPropertyElementMaster };
+            err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr, drvHostCoreAudioDeviceStateChangedCb,
+                                                 (void *)&pStreamOut->cbCtx);
+            if (err == noErr)
+            {
+                pStreamOut->fDevStateChgListReg = true;
+            }
+            else
+                LogRel(("CoreAudio: Failed to add the playback device state changed listener (%RI32)\n", err));
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvHostCoreAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    NOREF(pInterface);
+    NOREF(enmDir);
+    return true; /* Always all enabled. */
+}
+
+static DECLCALLBACK(int) drvHostCoreAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    PPDMDRVINS        pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTCOREAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
+
+    return coreAudioUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
+}
+
+static DECLCALLBACK(void) drvHostCoreAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+}
+
+static DECLCALLBACK(void *) drvHostCoreAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS        pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTCOREAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+
+    return NULL;
+}
+
+ /* Construct a DirectSound Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostCoreAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(pCfg, fFlags);
+    PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
+    LogRel(("Audio: Initializing Core Audio driver\n"));
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostCoreAudioQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostCoreAudio);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Char driver registration record.
+ */
+const PDMDRVREG g_DrvHostCoreAudio =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "CoreAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Core Audio host driver",
+    /* fFlags */
+     PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTCOREAUDIO),
+    /* pfnConstruct */
+    drvHostCoreAudioConstruct,
+    /* pfnDestruct */
+    NULL,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
diff --git a/src/VBox/Devices/Audio_50/DrvHostDSound.cpp b/src/VBox/Devices/Audio_50/DrvHostDSound.cpp
new file mode 100644
index 0000000..2f8889c
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvHostDSound.cpp
@@ -0,0 +1,2292 @@
+/* $Id: DrvHostDSound.cpp $ */
+/** @file
+ * Windows host backend driver using DirectSound.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ */
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+#include <iprt/win/windows.h>
+#include <dsound.h>
+
+#include <iprt/alloc.h>
+#include <iprt/uuid.h>
+
+#include "AudioMixBuffer.h"
+#include "DrvAudio.h"
+#include "VBoxDD.h"
+
+/*
+ * IDirectSound* interface uses HRESULT status codes and the driver callbacks use
+ * the IPRT status codes. To minimize HRESULT->IPRT conversion most internal functions
+ * in the driver return HRESULT and conversion is done in the driver callbacks.
+ *
+ * Naming convention:
+ * 'dsound*' functions return IPRT status code;
+ * 'directSound*' - return HRESULT.
+ */
+
+/*
+ * Optional release logging, which a user can turn on with the
+ * 'VBoxManage debugvm' command.
+ * Debug logging still uses the common Log* macros from IPRT.
+ * Messages which always should go to the release log use LogRel.
+ */
+/* General code behavior. */
+#define DSLOG(a) do { LogRel2(a); } while(0)
+/* Something which produce a lot of logging during playback/recording. */
+#define DSLOGF(a) do { LogRel3(a); } while(0)
+/* Important messages like errors. Limited in the default release log to avoid log flood. */
+#define DSLOGREL(a)                 \
+    do {                            \
+        static int8_t scLogged = 0; \
+        if (scLogged < 8) {         \
+            ++scLogged;             \
+            LogRel(a);              \
+        }                           \
+        else {                      \
+            DSLOG(a);               \
+        }                           \
+    } while (0)
+
+/* Dynamically load dsound.dll. */
+typedef HRESULT WINAPI FNDIRECTSOUNDENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
+typedef FNDIRECTSOUNDENUMERATEW *PFNDIRECTSOUNDENUMERATEW;
+typedef HRESULT WINAPI FNDIRECTSOUNDCAPTUREENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
+typedef FNDIRECTSOUNDCAPTUREENUMERATEW *PFNDIRECTSOUNDCAPTUREENUMERATEW;
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+# define VBOX_DSOUND_MAX_EVENTS 3
+
+typedef enum DSOUNDEVENT
+{
+    DSOUNDEVENT_NOTIFY = 0,
+    DSOUNDEVENT_INPUT,
+    DSOUNDEVENT_OUTPUT,
+ } DSOUNDEVENT;
+#endif /* VBOX_WITH_AUDIO_CALLBACKS */
+
+typedef struct DSOUNDHOSTCFG
+{
+    DWORD   cbBufferIn;
+    DWORD   cbBufferOut;
+    RTUUID  uuidPlay;
+    LPCGUID pGuidPlay;
+    RTUUID  uuidCapture;
+    LPCGUID pGuidCapture;
+} DSOUNDHOSTCFG, *PDSOUNDHOSTCFG;
+
+typedef struct DSOUNDSTREAMOUT
+{
+    PDMAUDIOHSTSTRMOUT   strmOut; /* Always must come first! */
+    LPDIRECTSOUND8       pDS;
+    LPDIRECTSOUNDBUFFER8 pDSB;
+    DWORD                cbPlayWritePos;
+    DWORD                csPlaybackBufferSize;
+    bool                 fEnabled;
+    bool                 fRestartPlayback;
+    PDMAUDIOSTREAMCFG    streamCfg;
+} DSOUNDSTREAMOUT, *PDSOUNDSTREAMOUT;
+
+typedef struct DSOUNDSTREAMIN
+{
+    PDMAUDIOHSTSTRMIN           strmIn; /* Always must come first! */
+    LPDIRECTSOUNDCAPTURE8       pDSC;
+    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
+    DWORD                       csCaptureReadPos;
+    DWORD                       csCaptureBufferSize;
+    HRESULT                     hrLastCaptureIn;
+    PDMAUDIORECSOURCE           enmRecSource;
+    bool                        fEnabled;
+    PDMAUDIOSTREAMCFG           streamCfg;
+} DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
+
+typedef struct DRVHOSTDSOUND
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS          pDrvIns;
+    /** Our audio host audio interface. */
+    PDMIHOSTAUDIO       IHostAudio;
+    /** List of found host input devices. */
+    RTLISTANCHOR        lstDevInput;
+    /** List of found host output devices. */
+    RTLISTANCHOR        lstDevOutput;
+    /** DirectSound configuration options. */
+    DSOUNDHOSTCFG       cfg;
+    /** Whether this backend supports any audio input. */
+    bool                fEnabledIn;
+    /** Whether this backend supports any audio output. */
+    bool                fEnabledOut;
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    /** Pointer to the audio connector interface of the driver/device above us. */
+    PPDMIAUDIOCONNECTOR pUpIAudioConnector;
+    /** Stopped indicator. */
+    bool                fStopped;
+    /** Shutdown indicator. */
+    bool                fShutdown;
+    /** Notification thread. */
+    RTTHREAD            Thread;
+    /** Array of events to wait for in notification thread. */
+    HANDLE              aEvents[VBOX_DSOUND_MAX_EVENTS];
+    /** Number of events to wait for in notification thread.
+     *  Must not exceed VBOX_DSOUND_MAX_EVENTS. */
+    uint8_t             cEvents;
+    /** Pointer to the input stream. */
+    PDSOUNDSTREAMIN     pDSStrmIn;
+    /** Pointer to the output stream. */
+    PDSOUNDSTREAMOUT    pDSStrmOut;
+#endif
+} DRVHOSTDSOUND, *PDRVHOSTDSOUND;
+
+/** No flags specified. */
+#define DSOUNDENUMCBFLAGS_NONE          0
+/** (Release) log found devices. */
+#define DSOUNDENUMCBFLAGS_LOG           RT_BIT(0)
+
+/**
+ * Callback context for enumeration callbacks
+ */
+typedef struct DSOUNDENUMCBCTX
+{
+    PDRVHOSTDSOUND      pDrv;
+    PPDMAUDIOBACKENDCFG pCfg;
+    /** Enumeration flags. */
+    uint32_t            fFlags;
+} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
+
+typedef struct DSOUNDDEV
+{
+    RTLISTNODE  Node;
+    char       *pszName;
+    GUID        Guid;
+} DSOUNDDEV, *PDSOUNDDEV;
+
+/** Maximum number of attempts to restore the sound buffer before giving up. */
+#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX         3
+
+/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
+#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
+    ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
+
+static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
+
+static void dsoundDeviceRemove(PDSOUNDDEV pDev);
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
+#endif
+
+static DWORD dsoundRingDistance(DWORD offEnd, DWORD offBegin, DWORD cSize)
+{
+    return offEnd >= offBegin ? offEnd - offBegin : cSize - offBegin + offEnd;
+}
+
+static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
+{
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+    AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
+
+    RT_BZERO(pFmt, sizeof(WAVEFORMATEX));
+
+    pFmt->wFormatTag      = WAVE_FORMAT_PCM;
+    pFmt->nChannels       = pCfg->cChannels;
+    pFmt->nSamplesPerSec  = pCfg->uHz;
+    pFmt->nAvgBytesPerSec = pCfg->uHz << (pCfg->cChannels == 2 ? 1: 0);
+    pFmt->nBlockAlign     = 1 << (pCfg->cChannels == 2 ? 1: 0);
+    pFmt->cbSize          = 0; /* No extra data specified. */
+
+    switch (pCfg->enmFormat)
+    {
+        case AUD_FMT_S8:
+        case AUD_FMT_U8:
+            pFmt->wBitsPerSample = 8;
+            break;
+
+        case AUD_FMT_S16:
+        case AUD_FMT_U16:
+            pFmt->wBitsPerSample = 16;
+            pFmt->nAvgBytesPerSec <<= 1;
+            pFmt->nBlockAlign <<= 1;
+            break;
+
+        case AUD_FMT_S32:
+        case AUD_FMT_U32:
+            pFmt->wBitsPerSample = 32;
+            pFmt->nAvgBytesPerSec <<= 2;
+            pFmt->nBlockAlign <<= 2;
+            break;
+
+        default:
+            AssertMsgFailed(("Wave format %ld not supported\n", pCfg->enmFormat));
+            return VERR_NOT_SUPPORTED;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int dsoundGetPosOut(PDRVHOSTDSOUND   pThis,
+                           PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
+{
+    AssertPtrReturn(pThis,          VERR_INVALID_POINTER);
+    AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
+
+    LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
+    if (!pDSB)
+        return VERR_INVALID_POINTER;
+
+    DWORD cbBuffer = AUDIOMIXBUF_S2B(&pDSoundStrmOut->strmOut.MixBuf, pDSoundStrmOut->csPlaybackBufferSize);
+
+    /* Get the current play position which is used for calculating the free space in the buffer. */
+    DWORD cbPlayPos = 0;
+
+    HRESULT hr = E_FAIL;
+    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+    {
+        hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
+        if (   SUCCEEDED(hr)
+            || hr != DSERR_BUFFERLOST) /** @todo: MSDN doesn't state this error for GetCurrentPosition(). */
+            break;
+        LogFlowFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
+        directSoundPlayRestore(pThis, pDSB);
+    }
+
+    int rc = VINF_SUCCESS;
+
+    if (FAILED(hr))
+    {
+        if (hr != DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
+            DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
+        LogFlowFunc(("Failed with %Rhrc\n", hr));
+
+        rc = VERR_NOT_AVAILABLE;
+    }
+    else
+    {
+        if (pdwBuffer)
+            *pdwBuffer = cbBuffer;
+
+        if (pdwFree)
+            *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
+
+        if (pdwPlayPos)
+            *pdwPlayPos = cbPlayPos;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static char *dsoundGUIDToUtf8StrA(LPCGUID lpGUID)
+{
+    if (lpGUID)
+    {
+        LPOLESTR lpOLEStr;
+        HRESULT hr = StringFromCLSID(*lpGUID, &lpOLEStr);
+        if (SUCCEEDED(hr))
+        {
+            char *pszGUID;
+            int rc = RTUtf16ToUtf8(lpOLEStr, &pszGUID);
+            CoTaskMemFree(lpOLEStr);
+
+            return RT_SUCCESS(rc) ? pszGUID : NULL;
+        }
+    }
+
+    return RTStrDup("{Default device}");
+}
+
+/**
+ * Clears the list of the host's playback + capturing devices.
+ *
+ * @param   pThis               Host audio driver instance.
+ */
+static void dsoundDevicesClear(PDRVHOSTDSOUND pThis)
+{
+    AssertPtrReturnVoid(pThis);
+
+    PDSOUNDDEV pDev;
+    while (!RTListIsEmpty(&pThis->lstDevInput))
+    {
+        pDev = RTListGetFirst(&pThis->lstDevInput, DSOUNDDEV, Node);
+        dsoundDeviceRemove(pDev);
+    }
+
+    while (!RTListIsEmpty(&pThis->lstDevOutput))
+    {
+        pDev = RTListGetFirst(&pThis->lstDevOutput, DSOUNDDEV, Node);
+        dsoundDeviceRemove(pDev);
+    }
+}
+
+static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
+{
+    RT_NOREF(pThis);
+    HRESULT hr = IDirectSoundBuffer8_Restore(pDSB);
+    if (FAILED(hr))
+        DSLOGREL(("DSound: Restoring playback buffer failed with %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
+                                     LPVOID pv1, LPVOID pv2,
+                                     DWORD cb1, DWORD cb2)
+{
+    RT_NOREF(pThis);
+    HRESULT hr = IDirectSoundBuffer8_Unlock(pDSB, pv1, cb1, pv2, cb2);
+    if (FAILED(hr))
+        DSLOGREL(("DSound: Unlocking playback buffer failed with %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
+                                        LPVOID pv1, LPVOID pv2,
+                                        DWORD cb1, DWORD cb2)
+{
+    HRESULT hr = IDirectSoundCaptureBuffer8_Unlock(pDSCB, pv1, cb1, pv2, cb2);
+    if (FAILED(hr))
+        DSLOGREL(("DSound: Unlocking capture buffer failed with %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis,
+                                   LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
+                                   DWORD dwOffset, DWORD dwBytes,
+                                   LPVOID *ppv1, LPVOID *ppv2,
+                                   DWORD *pcb1, DWORD *pcb2,
+                                   DWORD dwFlags)
+{
+    LPVOID pv1 = NULL;
+    LPVOID pv2 = NULL;
+    DWORD cb1 = 0;
+    DWORD cb2 = 0;
+
+    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+    {
+        HRESULT hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
+        if (SUCCEEDED(hr))
+            break;
+        if (hr != DSERR_BUFFERLOST)
+        {
+            DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc\n", hr));
+            return hr;
+        }
+        LogFlowFunc(("Locking failed due to lost buffer, restoring ...\n"));
+        directSoundPlayRestore(pThis, pDSB);
+    }
+
+    if (   (pv1 && (cb1 & pProps->uAlign))
+        || (pv2 && (cb2 & pProps->uAlign)))
+    {
+        DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
+                  cb1, cb2, pProps->uAlign));
+        directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
+        return E_FAIL;
+    }
+
+    *ppv1 = pv1;
+    *ppv2 = pv2;
+    *pcb1 = cb1;
+    *pcb2 = cb2;
+
+    return S_OK;
+}
+
+static HRESULT directSoundCaptureLock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB, PPDMPCMPROPS pProps,
+                                      DWORD dwOffset, DWORD dwBytes,
+                                      LPVOID *ppv1, LPVOID *ppv2,
+                                      DWORD *pcb1, DWORD *pcb2,
+                                      DWORD dwFlags)
+{
+    LPVOID pv1 = NULL;
+    LPVOID pv2 = NULL;
+    DWORD cb1 = 0;
+    DWORD cb2 = 0;
+
+    HRESULT hr = IDirectSoundCaptureBuffer8_Lock(pDSCB, dwOffset, dwBytes,
+                                                 &pv1, &cb1, &pv2, &cb2, dwFlags);
+    if (FAILED(hr))
+    {
+        DSLOGREL(("DSound: Locking capture buffer failed with %Rhrc\n", hr));
+        return hr;
+    }
+
+    if (   (pv1 && (cb1 & pProps->uAlign))
+        || (pv2 && (cb2 & pProps->uAlign)))
+    {
+        DSLOGREL(("DSound: Locking capture buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
+                  cb1, cb2, pProps->uAlign));
+        directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
+        return E_FAIL;
+    }
+
+    *ppv1 = pv1;
+    *ppv2 = pv2;
+    *pcb1 = cb1;
+    *pcb2 = cb2;
+
+    return S_OK;
+}
+
+
+/*
+ * DirectSound playback
+ */
+
+static void directSoundPlayInterfaceRelease(PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    if (pDSoundStrmOut->pDS)
+    {
+        IDirectSound8_Release(pDSoundStrmOut->pDS);
+        pDSoundStrmOut->pDS = NULL;
+    }
+}
+
+static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    if (pDSoundStrmOut->pDS != NULL)
+    {
+        DSLOG(("DSound: DirectSound instance already exists\n"));
+        return S_OK;
+    }
+
+    HRESULT hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL,
+                                  IID_IDirectSound8, (void **)&pDSoundStrmOut->pDS);
+    if (FAILED(hr))
+    {
+        DSLOGREL(("DSound: Creating playback instance failed with %Rhrc\n", hr));
+    }
+    else
+    {
+        hr = IDirectSound8_Initialize(pDSoundStrmOut->pDS, pThis->cfg.pGuidPlay);
+        if (SUCCEEDED(hr))
+        {
+            HWND hWnd = GetDesktopWindow();
+            hr = IDirectSound8_SetCooperativeLevel(pDSoundStrmOut->pDS, hWnd, DSSCL_PRIORITY);
+            if (FAILED(hr))
+                DSLOGREL(("DSound: Setting cooperative level for window %p failed with %Rhrc\n", hWnd, hr));
+        }
+
+        if (FAILED(hr))
+        {
+            if (hr == DSERR_NODRIVER) /* Usually means that no playback devices are attached. */
+                DSLOGREL(("DSound: DirectSound playback is currently unavailable\n"));
+            else
+                DSLOGREL(("DSound: DirectSound playback initialization failed with %Rhrc\n", hr));
+
+            directSoundPlayInterfaceRelease(pDSoundStrmOut);
+        }
+    }
+
+    return hr;
+}
+
+static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    AssertPtrReturn(pThis, E_POINTER);
+    AssertPtrReturn(pDSoundStrmOut, E_POINTER);
+
+    DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pDSoundStrmOut, pDSoundStrmOut->pDSB));
+
+    HRESULT hr = S_OK;
+
+    if (pDSoundStrmOut->pDSB)
+    {
+        hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
+        if (SUCCEEDED(hr))
+        {
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+            if (pThis->aEvents[DSOUNDEVENT_OUTPUT] != NULL)
+            {
+                CloseHandle(pThis->aEvents[DSOUNDEVENT_OUTPUT]);
+                pThis->aEvents[DSOUNDEVENT_OUTPUT] = NULL;
+
+                if (pThis->cEvents)
+                    pThis->cEvents--;
+
+                pThis->pDSStrmOut = NULL;
+            }
+
+            int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */);
+            AssertRC(rc2);
+#endif
+            IDirectSoundBuffer8_Release(pDSoundStrmOut->pDSB);
+            pDSoundStrmOut->pDSB = NULL;
+        }
+        else
+            DSLOGREL(("DSound: Stop playback stream %p when closing %Rhrc\n", pDSoundStrmOut, hr));
+    }
+
+    if (SUCCEEDED(hr))
+        directSoundPlayInterfaceRelease(pDSoundStrmOut);
+
+    return hr;
+}
+
+static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    AssertPtrReturn(pThis, E_POINTER);
+    AssertPtrReturn(pDSoundStrmOut, E_POINTER);
+
+    DSLOG(("DSound: pDSoundStrmOut=%p, cbBufferOut=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
+           pDSoundStrmOut,
+           pThis->cfg.cbBufferOut,
+           pDSoundStrmOut->strmOut.Props.uHz,
+           pDSoundStrmOut->strmOut.Props.cChannels,
+           pDSoundStrmOut->strmOut.Props.cBits,
+           pDSoundStrmOut->strmOut.Props.fSigned));
+
+    if (pDSoundStrmOut->pDSB != NULL)
+    {
+        /* Should not happen but be forgiving. */
+        DSLOGREL(("DSound: Playback buffer already exists\n"));
+        directSoundPlayClose(pThis, pDSoundStrmOut);
+    }
+
+    WAVEFORMATEX wfx;
+    int rc = dsoundWaveFmtFromCfg(&pDSoundStrmOut->streamCfg, &wfx);
+    if (RT_FAILURE(rc))
+        return E_INVALIDARG;
+
+    HRESULT hr = directSoundPlayInterfaceCreate(pThis, pDSoundStrmOut);
+    if (FAILED(hr))
+        return hr;
+
+    do /* To use breaks. */
+    {
+        LPDIRECTSOUNDBUFFER pDSB = NULL;
+
+        DSBUFFERDESC bd;
+        RT_ZERO(bd);
+        bd.dwSize      = sizeof(bd);
+        bd.lpwfxFormat = &wfx;
+
+        /*
+         * As we reuse our (secondary) buffer for playing out data as it comes in,
+         * we're using this buffer as a so-called static buffer.
+         *
+         * However, as we do not want to use memory on the sound device directly
+         * (as most modern audio hardware on the host doesn't have this anyway),
+         * we're *not* going to use DSBCAPS_STATIC for that.
+         *
+         * Instead we're specifying DSBCAPS_LOCSOFTWARE, as this fits the bill
+         * of copying own buffer data (from AudioMixBuf) to our secondary's Direct Sound buffer.
+         */
+        bd.dwFlags     = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+        bd.dwFlags    |= DSBCAPS_CTRLPOSITIONNOTIFY;
+#endif
+        bd.dwBufferBytes = pThis->cfg.cbBufferOut;
+
+        hr = IDirectSound8_CreateSoundBuffer(pDSoundStrmOut->pDS, &bd, &pDSB, NULL);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Creating playback sound buffer failed with %Rhrc\n", hr));
+            break;
+        }
+
+        /* "Upgrade" to IDirectSoundBuffer8 interface. */
+        hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (LPVOID *)&pDSoundStrmOut->pDSB);
+        IDirectSoundBuffer_Release(pDSB);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Querying playback sound buffer interface failed with %Rhrc\n", hr));
+            break;
+        }
+
+        /*
+         * Query the actual parameters.
+         */
+        hr = IDirectSoundBuffer8_GetFormat(pDSoundStrmOut->pDSB, &wfx, sizeof(wfx), NULL);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Getting playback format failed with %Rhrc\n", hr));
+            break;
+        }
+
+        DSBCAPS bc;
+        RT_ZERO(bc);
+        bc.dwSize = sizeof(bc);
+        hr = IDirectSoundBuffer8_GetCaps(pDSoundStrmOut->pDSB, &bc);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Getting playback capabilities failed with %Rhrc\n", hr));
+            break;
+        }
+
+        DSLOG(("DSound: Playback format:\n"
+               "  dwBufferBytes   = %RI32\n"
+               "  dwFlags         = 0x%x\n"
+               "  wFormatTag      = %RI16\n"
+               "  nChannels       = %RI16\n"
+               "  nSamplesPerSec  = %RU32\n"
+               "  nAvgBytesPerSec = %RU32\n"
+               "  nBlockAlign     = %RI16\n"
+               "  wBitsPerSample  = %RI16\n"
+               "  cbSize          = %RI16\n",
+               bc.dwBufferBytes,
+               bc.dwFlags,
+               wfx.wFormatTag,
+               wfx.nChannels,
+               wfx.nSamplesPerSec,
+               wfx.nAvgBytesPerSec,
+               wfx.nBlockAlign,
+               wfx.wBitsPerSample,
+               wfx.cbSize));
+
+        if (bc.dwBufferBytes & pDSoundStrmOut->strmOut.Props.uAlign)
+            DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n",
+                      bc.dwBufferBytes, pDSoundStrmOut->strmOut.Props.uAlign + 1));
+
+        if (bc.dwBufferBytes != pThis->cfg.cbBufferOut)
+            DSLOGREL(("DSound: Playback buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
+                      bc.dwBufferBytes, pThis->cfg.cbBufferOut));
+
+        /*
+         * Initial state.
+         * dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
+         * playback buffer position.
+         */
+        pDSoundStrmOut->csPlaybackBufferSize = bc.dwBufferBytes >> pDSoundStrmOut->strmOut.Props.cShift;
+        DSLOG(("DSound: csPlaybackBufferSize=%RU32\n", pDSoundStrmOut->csPlaybackBufferSize));
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+        /*
+         * Install notification.
+         */
+        pThis->aEvents[DSOUNDEVENT_OUTPUT] = CreateEvent(NULL /* Security attribute */,
+                                                         FALSE /* bManualReset */, FALSE /* bInitialState */,
+                                                         NULL /* lpName */);
+        if (pThis->aEvents[DSOUNDEVENT_OUTPUT] == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            DSLOGREL(("DSound: CreateEvent for output failed with %Rhrc\n", hr));
+            break;
+        }
+
+        LPDIRECTSOUNDNOTIFY8 pNotify;
+        hr = IDirectSoundNotify_QueryInterface(pDSoundStrmOut->pDSB, IID_IDirectSoundNotify8, (LPVOID *)&pNotify);
+        if (SUCCEEDED(hr))
+        {
+            DSBPOSITIONNOTIFY dsBufPosNotify;
+            RT_ZERO(dsBufPosNotify);
+            dsBufPosNotify.dwOffset     = DSBPN_OFFSETSTOP;
+            dsBufPosNotify.hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
+
+            hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 1 /* Count */, &dsBufPosNotify);
+            if (FAILED(hr))
+                DSLOGREL(("DSound: Setting playback position notification failed with %Rhrc\n", hr));
+
+            IDirectSoundNotify_Release(pNotify);
+        }
+        else
+            DSLOGREL(("DSound: Querying interface for position notification failed with %Rhrc\n", hr));
+
+        if (FAILED(hr))
+            break;
+
+        pThis->pDSStrmOut = pDSoundStrmOut;
+
+        Assert(pThis->cEvents < VBOX_DSOUND_MAX_EVENTS);
+        pThis->cEvents++;
+
+        /* Let the thread know. */
+        dsoundNotifyThread(pThis, false /* fShutdown */);
+
+        /* Trigger the just installed output notification. */
+        hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, 0);
+
+#endif /* VBOX_WITH_AUDIO_CALLBACKS */
+
+    } while (0);
+
+    if (FAILED(hr))
+        directSoundPlayClose(pThis, pDSoundStrmOut);
+
+    return hr;
+}
+
+static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    AssertPtrReturnVoid(pDSoundStrmOut);
+
+    PPDMAUDIOHSTSTRMOUT pStrmOut = &pDSoundStrmOut->strmOut;
+
+    LPVOID pv1, pv2;
+    DWORD cb1, cb2;
+    HRESULT hr = directSoundPlayLock(pThis, pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
+                                     0 /* dwOffset */, AUDIOMIXBUF_S2B(&pStrmOut->MixBuf, pDSoundStrmOut->csPlaybackBufferSize),
+                                     &pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
+    if (SUCCEEDED(hr))
+    {
+        DWORD len1 = AUDIOMIXBUF_B2S(&pStrmOut->MixBuf, cb1);
+        DWORD len2 = AUDIOMIXBUF_B2S(&pStrmOut->MixBuf, cb2);
+
+        if (pv1 && len1)
+            DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv1, cb1, len1);
+
+        if (pv2 && len2)
+            DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv2, cb2, len2);
+
+        directSoundPlayUnlock(pThis, pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
+    }
+}
+
+static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
+{
+    AssertPtrReturn(pThis, E_POINTER);
+    AssertPtrReturn(pDSB,  E_POINTER);
+    /* pdwStatus is optional. */
+
+    DWORD dwStatus = 0;
+
+    HRESULT hr = E_FAIL;
+    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+    {
+        hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
+        if (   hr == DSERR_BUFFERLOST
+            || (   SUCCEEDED(hr)
+                && (dwStatus & DSBSTATUS_BUFFERLOST)))
+        {
+            LogFlowFunc(("Getting status failed due to lost buffer, restoring ...\n"));
+            directSoundPlayRestore(pThis, pDSB);
+        }
+        else
+            break;
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        if (pdwStatus)
+            *pdwStatus = dwStatus;
+    }
+    else
+        DSLOGREL(("DSound: Retrieving playback status failed with %Rhrc\n", hr));
+
+    return hr;
+}
+
+static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    AssertPtrReturn(pThis,          E_POINTER);
+    AssertPtrReturn(pDSoundStrmOut, E_POINTER);
+
+    HRESULT hr;
+
+    if (pDSoundStrmOut->pDSB != NULL)
+    {
+        DSLOG(("DSound: Stopping playback\n"));
+
+        HRESULT hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
+        if (FAILED(hr2))
+        {
+            hr2 = directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
+            if (FAILED(hr2))
+                hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
+        }
+
+        if (FAILED(hr2))
+            DSLOG(("DSound: Stopping playback failed with %Rhrc\n", hr2));
+
+        hr = S_OK; /* Always report success here. */
+    }
+    else
+        hr = E_UNEXPECTED;
+
+    if (SUCCEEDED(hr))
+    {
+        dsoundPlayClearSamples(pThis, pDSoundStrmOut);
+        pDSoundStrmOut->fEnabled = false;
+    }
+    else
+        DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));
+
+    return hr;
+}
+
+static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    AssertPtrReturn(pThis,          E_POINTER);
+    AssertPtrReturn(pDSoundStrmOut, E_POINTER);
+
+    HRESULT hr;
+    if (pDSoundStrmOut->pDSB != NULL)
+    {
+        DWORD dwStatus;
+        hr = directSoundPlayGetStatus(pThis, pDSoundStrmOut->pDSB, &dwStatus);
+        if (SUCCEEDED(hr))
+        {
+            if (dwStatus & DSBSTATUS_PLAYING)
+            {
+                DSLOG(("DSound: Already playing\n"));
+            }
+            else
+            {
+                dsoundPlayClearSamples(pThis, pDSoundStrmOut);
+
+                pDSoundStrmOut->fRestartPlayback = true;
+                pDSoundStrmOut->fEnabled         = true;
+
+                DSLOG(("DSound: Playback started\n"));
+
+                /*
+                 * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
+                 * because it is necessary to put some samples into the buffer first.
+                 */
+            }
+        }
+    }
+    else
+        hr = E_UNEXPECTED;
+
+    if (FAILED(hr))
+        DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr));
+
+    return hr;
+}
+
+/*
+ * DirectSoundCapture
+ */
+
+static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    AssertPtrReturn(pThis, NULL);
+    AssertPtrReturn(pDSoundStrmIn, NULL);
+
+    LPCGUID pGUID = pThis->cfg.pGuidCapture;
+
+    if (!pGUID)
+    {
+        PDSOUNDDEV  pDev = NULL;
+
+        switch (pDSoundStrmIn->enmRecSource)
+        {
+            case PDMAUDIORECSOURCE_MIC:
+            {
+                RTListForEach(&pThis->lstDevInput, pDev, DSOUNDDEV, Node)
+                {
+                    if (RTStrIStr(pDev->pszName, "Mic")) /** @todo what is with non en_us windows versions? */
+                        break;
+                }
+                if (RTListNodeIsDummy(&pThis->lstDevInput, pDev, DSOUNDDEV, Node))
+                    pDev = NULL;    /* Found nothing. */
+
+                break;
+            }
+
+            case PDMAUDIORECSOURCE_LINE_IN:
+            default:
+                /* Try opening the default device (NULL). */
+                break;
+        }
+
+        if (pDev)
+        {
+            DSLOG(("DSound: Guest \"%s\" is using host \"%s\"\n",
+                   drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pDev->pszName));
+
+            pGUID = &pDev->Guid;
+        }
+    }
+
+    char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
+    /* This always has to be in the release log. */
+    LogRel(("DSound: Guest \"%s\" is using host device with GUID: %s\n",
+            drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pszGUID? pszGUID: "{?}"));
+    RTStrFree(pszGUID);
+
+    return pGUID;
+}
+
+static void directSoundCaptureInterfaceRelease(PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    if (pDSoundStrmIn->pDSC)
+    {
+        LogFlowFuncEnter();
+        IDirectSoundCapture_Release(pDSoundStrmIn->pDSC);
+        pDSoundStrmIn->pDSC = NULL;
+    }
+}
+
+static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    if (pDSoundStrmIn->pDSC != NULL)
+    {
+        DSLOG(("DSound: DirectSoundCapture instance already exists\n"));
+        return S_OK;
+    }
+
+    HRESULT hr = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL,
+                                  IID_IDirectSoundCapture8, (void **)&pDSoundStrmIn->pDSC);
+    if (FAILED(hr))
+    {
+        DSLOGREL(("DSound: Creating capture instance failed with %Rhrc\n", hr));
+    }
+    else
+    {
+        LPCGUID pGUID = dsoundCaptureSelectDevice(pThis, pDSoundStrmIn);
+        hr = IDirectSoundCapture_Initialize(pDSoundStrmIn->pDSC, pGUID);
+        if (FAILED(hr))
+        {
+            if (hr == DSERR_NODRIVER) /* Usually means that no capture devices are attached. */
+                DSLOGREL(("DSound: Capture device currently is unavailable\n"));
+            else
+                DSLOGREL(("DSound: Initializing capturing device failed with %Rhrc\n", hr));
+
+            directSoundCaptureInterfaceRelease(pDSoundStrmIn);
+        }
+    }
+
+    LogFlowFunc(("Returning %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundCaptureClose(PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    AssertPtrReturn(pDSoundStrmIn, E_POINTER);
+
+    DSLOG(("DSound: pDSoundStrmIn=%p, pDSCB=%p\n", pDSoundStrmIn, pDSoundStrmIn->pDSCB));
+
+    HRESULT hr = S_OK;
+
+    if (pDSoundStrmIn->pDSCB)
+    {
+        hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
+        if (SUCCEEDED(hr))
+        {
+            IDirectSoundCaptureBuffer8_Release(pDSoundStrmIn->pDSCB);
+            pDSoundStrmIn->pDSCB = NULL;
+        }
+        else
+            DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
+    }
+
+    if (SUCCEEDED(hr))
+        directSoundCaptureInterfaceRelease(pDSoundStrmIn);
+
+    LogFlowFunc(("Returning %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    AssertPtrReturn(pThis, E_POINTER);
+    AssertPtrReturn(pDSoundStrmIn, E_POINTER);
+
+    DSLOG(("DSound: pDSoundStrmIn=%p, cbBufferIn=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
+           pDSoundStrmIn,
+           pThis->cfg.cbBufferIn,
+           pDSoundStrmIn->strmIn.Props.uHz,
+           pDSoundStrmIn->strmIn.Props.cChannels,
+           pDSoundStrmIn->strmIn.Props.cBits,
+           pDSoundStrmIn->strmIn.Props.fSigned));
+
+    if (pDSoundStrmIn->pDSCB != NULL)
+    {
+        /* Should not happen but be forgiving. */
+        DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));
+        directSoundCaptureClose(pDSoundStrmIn);
+    }
+
+    WAVEFORMATEX wfx;
+    int rc = dsoundWaveFmtFromCfg(&pDSoundStrmIn->streamCfg, &wfx);
+    if (RT_FAILURE(rc))
+        return E_INVALIDARG;
+
+    HRESULT hr = directSoundCaptureInterfaceCreate(pThis, pDSoundStrmIn);
+    if (FAILED(hr))
+        return hr;
+
+    do /* To use breaks. */
+    {
+        LPDIRECTSOUNDCAPTUREBUFFER pDSCB = NULL;
+        DSCBUFFERDESC bd;
+        RT_ZERO(bd);
+        bd.dwSize = sizeof(bd);
+        bd.lpwfxFormat = &wfx;
+        bd.dwBufferBytes = pThis->cfg.cbBufferIn;
+        hr = IDirectSoundCapture_CreateCaptureBuffer(pDSoundStrmIn->pDSC,
+                                                     &bd, &pDSCB, NULL);
+        if (FAILED(hr))
+        {
+            if (hr == E_ACCESSDENIED)
+            {
+                DSLOGREL(("DSound: Capturing input from host not possible, access denied\n"));
+            }
+            else
+                DSLOGREL(("DSound: Creating capture buffer failed with %Rhrc\n", hr));
+            break;
+        }
+
+        hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pDSoundStrmIn->pDSCB);
+        IDirectSoundCaptureBuffer_Release(pDSCB);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Querying interface for capture buffer failed with %Rhrc\n", hr));
+            break;
+        }
+
+        /*
+         * Query the actual parameters.
+         */
+        DWORD cbReadPos = 0;
+        hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pDSoundStrmIn->pDSCB, NULL, &cbReadPos);
+        if (FAILED(hr))
+        {
+            cbReadPos = 0;
+            DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
+        }
+
+        RT_ZERO(wfx);
+        hr = IDirectSoundCaptureBuffer8_GetFormat(pDSoundStrmIn->pDSCB, &wfx, sizeof(wfx), NULL);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Getting capture format failed with %Rhrc\n", hr));
+            break;
+        }
+
+        DSCBCAPS bc;
+        RT_ZERO(bc);
+        bc.dwSize = sizeof(bc);
+        hr = IDirectSoundCaptureBuffer8_GetCaps(pDSoundStrmIn->pDSCB, &bc);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("Getting capture capabilities failed with %Rhrc\n", hr));
+            break;
+        }
+
+        DSLOG(("DSound: Capture format:\n"
+               "  dwBufferBytes   = %RI32\n"
+               "  dwFlags         = 0x%x\n"
+               "  wFormatTag      = %RI16\n"
+               "  nChannels       = %RI16\n"
+               "  nSamplesPerSec  = %RU32\n"
+               "  nAvgBytesPerSec = %RU32\n"
+               "  nBlockAlign     = %RI16\n"
+               "  wBitsPerSample  = %RI16\n"
+               "  cbSize          = %RI16\n",
+               bc.dwBufferBytes,
+               bc.dwFlags,
+               wfx.wFormatTag,
+               wfx.nChannels,
+               wfx.nSamplesPerSec,
+               wfx.nAvgBytesPerSec,
+               wfx.nBlockAlign,
+               wfx.wBitsPerSample,
+               wfx.cbSize));
+
+        if (bc.dwBufferBytes & pDSoundStrmIn->strmIn.Props.uAlign)
+            DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n",
+                      bc.dwBufferBytes, pDSoundStrmIn->strmIn.Props.uAlign + 1));
+
+        if (bc.dwBufferBytes != pThis->cfg.cbBufferIn)
+            DSLOGREL(("DSound: Capture buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
+                      bc.dwBufferBytes, pThis->cfg.cbBufferIn));
+
+        /* Initial state: reading at the initial capture position, no error. */
+        pDSoundStrmIn->csCaptureReadPos    = cbReadPos >> pDSoundStrmIn->strmIn.Props.cShift;
+        pDSoundStrmIn->csCaptureBufferSize = bc.dwBufferBytes >> pDSoundStrmIn->strmIn.Props.cShift;
+        pDSoundStrmIn->hrLastCaptureIn = S_OK;
+
+        DSLOG(("DSound: csCaptureReadPos=%RU32, csCaptureBufferSize=%RU32\n",
+                     pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize));
+
+    } while (0);
+
+    if (FAILED(hr))
+        directSoundCaptureClose(pDSoundStrmIn);
+
+    LogFlowFunc(("Returning %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    AssertPtrReturn(pThis        , E_POINTER);
+    AssertPtrReturn(pDSoundStrmIn, E_POINTER);
+
+    NOREF(pThis);
+
+    HRESULT hr;
+
+    if (pDSoundStrmIn->pDSCB)
+    {
+        DSLOG(("DSound: Stopping capture\n"));
+
+        hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
+        if (FAILED(hr))
+            DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
+    }
+    else
+        hr = E_UNEXPECTED;
+
+    if (SUCCEEDED(hr))
+        pDSoundStrmIn->fEnabled = false;
+
+    LogFlowFunc(("Returning %Rhrc\n", hr));
+    return hr;
+}
+
+static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pDSoundStrmIn, VERR_INVALID_POINTER);
+
+    HRESULT hr;
+    if (pDSoundStrmIn->pDSCB != NULL)
+    {
+        DWORD dwStatus;
+        hr = IDirectSoundCaptureBuffer8_GetStatus(pDSoundStrmIn->pDSCB, &dwStatus);
+        if (FAILED(hr))
+        {
+            DSLOGREL(("DSound: Retrieving capture status failed with %Rhrc\n", hr));
+        }
+        else
+        {
+            if (dwStatus & DSCBSTATUS_CAPTURING)
+            {
+                DSLOG(("DSound: Already capturing\n"));
+            }
+            else
+            {
+                DWORD fFlags = 0;
+#ifndef VBOX_WITH_AUDIO_CALLBACKS
+                fFlags |= DSCBSTART_LOOPING;
+#endif
+                DSLOG(("DSound: Starting to capture\n"));
+                hr = IDirectSoundCaptureBuffer8_Start(pDSoundStrmIn->pDSCB, fFlags);
+                if (FAILED(hr))
+                    DSLOGREL(("DSound: Starting to capture failed with %Rhrc\n", hr));
+            }
+        }
+    }
+    else
+        hr = E_UNEXPECTED;
+
+    if (SUCCEEDED(hr))
+        pDSoundStrmIn->fEnabled = true;
+
+    LogFlowFunc(("Returning %Rhrc\n", hr));
+    return hr;
+}
+
+static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID lpGUID,
+                        LPCWSTR lpwstrDescription, PDSOUNDDEV *ppDev)
+{
+    AssertPtrReturn(pList, VERR_INVALID_POINTER);
+    AssertPtrReturn(lpGUID, VERR_INVALID_POINTER);
+    AssertPtrReturn(lpwstrDescription, VERR_INVALID_POINTER);
+
+    PDSOUNDDEV pDev = (PDSOUNDDEV)RTMemAlloc(sizeof(DSOUNDDEV));
+    if (!pDev)
+        return VERR_NO_MEMORY;
+
+    int rc = RTUtf16ToUtf8(lpwstrDescription, &pDev->pszName);
+    if (RT_SUCCESS(rc))
+        memcpy(&pDev->Guid, lpGUID, sizeof(GUID));
+
+    if (RT_SUCCESS(rc))
+        RTListAppend(pList, &pDev->Node);
+
+    if (ppDev)
+        *ppDev = pDev;
+
+    return rc;
+}
+
+static void dsoundDeviceRemove(PDSOUNDDEV pDev)
+{
+    if (pDev)
+    {
+        RTStrFree(pDev->pszName);
+        pDev->pszName = NULL;
+
+        RTListNodeRemove(&pDev->Node);
+
+        RTMemFree(pDev);
+    }
+}
+
+static void dsoundLogDevice(const char *pszType, LPGUID lpGUID, LPCWSTR lpwstrDescription, LPCWSTR lpwstrModule)
+{
+    char *pszGUID = dsoundGUIDToUtf8StrA(lpGUID);
+    /* This always has to be in the release log. */
+    LogRel(("DSound: %s: GUID: %s [%ls] (Module: %ls)\n",
+            pszType, pszGUID? pszGUID: "{?}", lpwstrDescription, lpwstrModule));
+    RTStrFree(pszGUID);
+}
+
+static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
+                                                 LPCWSTR lpwstrModule, LPVOID lpContext)
+{
+    PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
+    AssertPtrReturn(pCtx, FALSE);
+    AssertPtrReturn(pCtx->pDrv, FALSE);
+    AssertPtrReturn(pCtx->pCfg, FALSE);
+
+    if (!lpGUID)
+        return TRUE;
+
+    AssertPtrReturn(lpwstrDescription, FALSE);
+    /* Do not care about lpwstrModule. */
+
+    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
+        dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
+
+    int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
+                          lpGUID, lpwstrDescription, NULL /* ppDev */);
+    if (RT_FAILURE(rc))
+        return FALSE; /* Abort enumeration. */
+
+    pCtx->pCfg->cMaxHstStrmsOut++;
+
+    return TRUE;
+}
+
+static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID lpGUID, LPCWSTR lpwstrDescription,
+                                                LPCWSTR lpwstrModule, LPVOID lpContext)
+{
+    PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
+    AssertPtrReturn(pCtx, FALSE);
+    AssertPtrReturn(pCtx->pDrv, FALSE);
+    AssertPtrReturn(pCtx->pCfg, FALSE);
+
+    if (!lpGUID)
+        return TRUE;
+
+    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
+        dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
+
+    int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
+                          lpGUID, lpwstrDescription, NULL /* ppDev */);
+    if (RT_FAILURE(rc))
+        return FALSE; /* Abort enumeration. */
+
+    pCtx->pCfg->cMaxHstStrmsIn++;
+
+    return TRUE;
+}
+
+/**
+ * Does a (Re-)enumeration of the host's playback + capturing devices.
+ *
+ * @return  IPRT status code.
+ * @param   pThis               Host audio driver instance.
+ * @param   pCfg                Where to store the enumeration results.
+ * @param   fEnum               Enumeration flags.
+ */
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
+
+    dsoundDevicesClear(pThis);
+
+    pCfg->cMaxHstStrmsOut = 0;
+    pCfg->cMaxHstStrmsIn  = 0;
+
+    RTLDRMOD hDSound = NULL;
+    int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
+    if (RT_SUCCESS(rc))
+    {
+        PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
+        PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
+
+        rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
+        if (RT_SUCCESS(rc))
+            rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
+
+        if (RT_SUCCESS(rc))
+        {
+            DSOUNDENUMCBCTX ctx = { pThis, pCfg, fEnum };
+
+            HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &ctx);
+            if (FAILED(hr))
+                LogRel2(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
+
+            hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &ctx);
+            if (FAILED(hr))
+                LogRel2(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
+        }
+
+        RTLdrClose(hDSound);
+    }
+    else
+    {
+        /* No dsound.dll on this system. */
+        LogRel2(("DSound: Could not load dsound.dll: %Rrc\n", rc));
+    }
+
+    return rc;
+}
+
+/**
+ * Updates this host driver's internal status, according to the global, overall input/output
+ * state and all connected (native) audio streams.
+ *
+ * @param   pThis               Host audio driver instance.
+ * @param   pCfg                Where to store the backend configuration. Optional.
+ * @param   fEnum               Enumeration flags.
+ */
+void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+{
+    AssertPtrReturnVoid(pThis);
+    /* pCfg is optional. */
+
+    PDMAUDIOBACKENDCFG Cfg;
+    RT_ZERO(Cfg);
+
+    Cfg.cbStreamOut = sizeof(DSOUNDSTREAMOUT);
+    Cfg.cbStreamIn  = sizeof(DSOUNDSTREAMIN);
+
+    int rc = dsoundDevicesEnumerate(pThis, &Cfg, fEnum);
+    AssertRC(rc);
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    if (   pThis->fEnabledOut != RT_BOOL(Cfg.cMaxHstStrmsOut)
+        || pThis->fEnabledIn  != RT_BOOL(Cfg.cMaxHstStrmsIn))
+    {
+        /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
+         *        let the connector know that something has changed within the host backend. */
+    }
+#else
+    pThis->fEnabledOut = RT_BOOL(Cfg.cMaxHstStrmsOut);
+    pThis->fEnabledIn  = RT_BOOL(Cfg.cMaxHstStrmsIn);
+#endif
+
+    if (pCfg)
+        memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
+
+    LogFlowFuncLeaveRC(rc);
+}
+
+void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
+{
+    dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
+}
+
+/*
+ * PDMIHOSTAUDIO
+ */
+
+static DECLCALLBACK(int) drvHostDSoundInitOut(PPDMIHOSTAUDIO pInterface,
+                                              PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                              PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                              uint32_t *pcSamples)
+{
+    RT_NOREF(pCfgReq, pCfgAcq);
+    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,     VERR_INVALID_POINTER);
+    /* pcSamples is optional. */
+
+    LogFlowFunc(("pHstStrmOut=%p, pCfg=%p\n", pHstStrmOut, pCfgReq));
+
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
+
+    pDSoundStrmOut->streamCfg = *pCfgReq;
+    pDSoundStrmOut->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+    int rc = DrvAudioStreamCfgToProps(&pDSoundStrmOut->streamCfg, &pDSoundStrmOut->strmOut.Props);
+    if (RT_SUCCESS(rc))
+    {
+        pDSoundStrmOut->pDS = NULL;
+        pDSoundStrmOut->pDSB = NULL;
+        pDSoundStrmOut->cbPlayWritePos = 0;
+        pDSoundStrmOut->fRestartPlayback = true;
+        pDSoundStrmOut->csPlaybackBufferSize = 0;
+
+        if (pcSamples)
+            *pcSamples = pThis->cfg.cbBufferOut >> pHstStrmOut->Props.cShift;
+
+        /* Try to open playback in case the device is already there. */
+        directSoundPlayOpen(pThis, pDSoundStrmOut);
+    }
+    else
+    {
+        RT_ZERO(pDSoundStrmOut->streamCfg);
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDSoundControlOut(PPDMIHOSTAUDIO pInterface,
+                                                 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("pHstStrmOut=%p, cmd=%d\n", pHstStrmOut, enmStreamCmd));
+
+    PDRVHOSTDSOUND   pThis          = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
+
+    int rc = VINF_SUCCESS;
+
+    HRESULT hr;
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_ENABLE\n"));
+            /* Try to start playback. If it fails, then reopen and try again. */
+            hr = directSoundPlayStart(pThis, pDSoundStrmOut);
+            if (FAILED(hr))
+            {
+                hr = directSoundPlayClose(pThis, pDSoundStrmOut);
+                if (SUCCEEDED(hr))
+                    hr = directSoundPlayOpen(pThis, pDSoundStrmOut);
+                if (SUCCEEDED(hr))
+                    hr = directSoundPlayStart(pThis, pDSoundStrmOut);
+            }
+
+            if (FAILED(hr))
+                rc = VERR_NOT_SUPPORTED;
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_DISABLE\n"));
+            hr = directSoundPlayStop(pThis, pDSoundStrmOut);
+            if (FAILED(hr))
+                rc = VERR_NOT_SUPPORTED;
+            break;
+        }
+
+        default:
+        {
+            AssertMsgFailed(("Invalid command: %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDSoundPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                              uint32_t *pcSamplesPlayed)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    /* pcSamplesPlayed is optional. */
+
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
+
+    int rc = VINF_SUCCESS;
+    uint32_t cReadTotal = 0;
+
+#ifdef DEBUG_andy
+    LogFlowFuncEnter();
+#endif
+
+    do /* to use 'break' */
+    {
+        DWORD cbBuffer, cbFree, cbPlayPos;
+        rc = dsoundGetPosOut(pThis, pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
+        if (RT_FAILURE(rc))
+            break;
+
+        /*
+         * Check for full buffer, do not allow the cbPlayWritePos to catch cbPlayPos during playback,
+         * i.e. always leave a free space for 1 audio sample.
+         */
+        const DWORD cbSample = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, 1);
+        if (cbFree <= cbSample)
+            break;
+        cbFree     -= cbSample;
+
+        uint32_t csLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+        uint32_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, csLive);
+
+        /* Do not write more than available space in the DirectSound playback buffer. */
+        cbLive = RT_MIN(cbFree, cbLive);
+
+        cbLive &= ~pHstStrmOut->Props.uAlign;
+        if (cbLive == 0 || cbLive > cbBuffer)
+        {
+            DSLOG(("DSound: cbLive=%RU32, cbBuffer=%ld, cbPlayWritePos=%ld, cbPlayPos=%ld\n",
+                   cbLive, cbBuffer, pDSoundStrmOut->cbPlayWritePos, cbPlayPos));
+            break;
+        }
+
+        LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
+        AssertPtr(pDSB);
+
+        LPVOID pv1, pv2;
+        DWORD cb1, cb2;
+        HRESULT hr = directSoundPlayLock(pThis, pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
+                                         &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
+        if (FAILED(hr))
+        {
+            rc = VERR_ACCESS_DENIED;
+            break;
+        }
+
+        DWORD len1 = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cb1);
+        /*DWORD len2 = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cb2);*/
+
+        uint32_t cRead = 0;
+
+        if (pv1 && cb1)
+        {
+            rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv1, cb1, &cRead);
+            if (RT_SUCCESS(rc))
+                cReadTotal += cRead;
+        }
+
+        if (   RT_SUCCESS(rc)
+            && cReadTotal == len1
+            && pv2 && cb2)
+        {
+            rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv2, cb2, &cRead);
+            if (RT_SUCCESS(rc))
+                cReadTotal += cRead;
+        }
+
+        directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
+
+        pDSoundStrmOut->cbPlayWritePos =
+            (pDSoundStrmOut->cbPlayWritePos + AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal)) % cbBuffer;
+
+        DSLOGF(("DSound: %RU32 (%RU32 samples) out of %RU32%s, buffer write pos %ld, rc=%Rrc\n",
+                AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal), cReadTotal, cbLive,
+                cbLive != AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal) ? " !!!": "",
+                pDSoundStrmOut->cbPlayWritePos, rc));
+
+        if (cReadTotal)
+        {
+            AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
+            rc = VINF_SUCCESS; /* Played something. */
+        }
+
+        if (RT_FAILURE(rc))
+            break;
+
+        if (pDSoundStrmOut->fRestartPlayback)
+        {
+            /*
+             * The playback has been just started.
+             * Some samples of the new sound have been copied to the buffer
+             * and it can start playing.
+             */
+            pDSoundStrmOut->fRestartPlayback = false;
+
+            DWORD fFlags = 0;
+#ifndef VBOX_WITH_AUDIO_CALLBACKS
+            fFlags |= DSCBSTART_LOOPING;
+#endif
+            for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+            {
+                hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
+                if (   SUCCEEDED(hr)
+                    || hr != DSERR_BUFFERLOST)
+                    break;
+                else
+                {
+                    LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
+                    directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
+                }
+            }
+
+            if (FAILED(hr))
+            {
+                DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr));
+                rc = VERR_NOT_SUPPORTED;
+                break;
+            }
+        }
+
+    } while (0);
+
+    if (RT_FAILURE(rc))
+    {
+        dsoundUpdateStatusInternal(pThis);
+    }
+    else
+    {
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = cReadTotal;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDSoundFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
+
+    directSoundPlayClose(pThis, pDSoundStrmOut);
+
+    pDSoundStrmOut->cbPlayWritePos = 0;
+    pDSoundStrmOut->fRestartPlayback = true;
+    pDSoundStrmOut->csPlaybackBufferSize = 0;
+
+    RT_ZERO(pDSoundStrmOut->streamCfg);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostDSoundInitIn(PPDMIHOSTAUDIO pInterface,
+                                             PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                             PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                             PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
+{
+    RT_NOREF(pCfgAcq);
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
+    /* pcSamples is optional. */
+
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+
+    LogFlowFunc(("pHstStrmIn=%p, pCfgReq=%p, enmRecSource=%ld\n",
+                 pHstStrmIn, pCfgReq, enmRecSource));
+
+    pDSoundStrmIn->streamCfg = *pCfgReq;
+    pDSoundStrmIn->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+    /** @todo caller should already init Props? */
+    int rc = DrvAudioStreamCfgToProps(&pDSoundStrmIn->streamCfg, &pHstStrmIn->Props);
+    if (RT_SUCCESS(rc))
+    {
+        /* Init the stream structure and save relevant information to it. */
+        pDSoundStrmIn->csCaptureReadPos = 0;
+        pDSoundStrmIn->csCaptureBufferSize = 0;
+        pDSoundStrmIn->pDSC = NULL;
+        pDSoundStrmIn->pDSCB = NULL;
+        pDSoundStrmIn->enmRecSource = enmRecSource;
+        pDSoundStrmIn->hrLastCaptureIn = S_OK;
+
+        if (pcSamples)
+            *pcSamples = pThis->cfg.cbBufferIn >> pHstStrmIn->Props.cShift;
+
+        /* Try to open capture in case the device is already there. */
+        directSoundCaptureOpen(pThis, pDSoundStrmIn);
+    }
+    else
+    {
+        RT_ZERO(pDSoundStrmIn->streamCfg);
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDSoundControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("pHstStrmIn=%p, enmStreamCmd=%ld\n", pHstStrmIn, enmStreamCmd));
+
+    PDRVHOSTDSOUND  pThis         = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+
+    int rc = VINF_SUCCESS;
+
+    HRESULT hr;
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            /* Try to start capture. If it fails, then reopen and try again. */
+            hr = directSoundCaptureStart(pThis, pDSoundStrmIn);
+            if (FAILED(hr))
+            {
+                hr = directSoundCaptureClose(pDSoundStrmIn);
+                if (SUCCEEDED(hr))
+                {
+                    hr = directSoundCaptureOpen(pThis, pDSoundStrmIn);
+                    if (SUCCEEDED(hr))
+                        hr = directSoundCaptureStart(pThis, pDSoundStrmIn);
+                }
+            }
+
+            if (FAILED(hr))
+                rc = VERR_NOT_SUPPORTED;
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            hr = directSoundCaptureStop(pThis, pDSoundStrmIn);
+            if (FAILED(hr))
+                rc = VERR_NOT_SUPPORTED;
+            break;
+        }
+
+        default:
+        {
+            AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+        }
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDSoundCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                uint32_t *pcSamplesCaptured)
+{
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+    PDSOUNDSTREAMIN             pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB         = pDSoundStrmIn->pDSCB;
+
+    int rc = VINF_SUCCESS;
+
+    uint32_t cCaptured = 0;
+
+    do
+    {
+        if (pDSCB == NULL)
+        {
+            rc = VERR_NOT_AVAILABLE;
+            break;
+        }
+
+        /* Get DirectSound capture position in bytes. */
+        DWORD cbReadPos;
+        HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &cbReadPos);
+        if (FAILED(hr))
+        {
+            if (hr != pDSoundStrmIn->hrLastCaptureIn)
+            {
+                DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
+                pDSoundStrmIn->hrLastCaptureIn = hr;
+            }
+
+            rc = VERR_NOT_AVAILABLE;
+            break;
+        }
+
+        pDSoundStrmIn->hrLastCaptureIn = hr;
+
+        if (cbReadPos & pHstStrmIn->Props.uAlign)
+            DSLOGF(("DSound: Misaligned capture read position %ld (alignment: %RU32)\n", cbReadPos, pHstStrmIn->Props.uAlign));
+
+        /* Capture position in samples. */
+        DWORD csReadPos = cbReadPos >> pHstStrmIn->Props.cShift;
+
+        /* Number of samples available in the DirectSound capture buffer. */
+        DWORD csCaptured = dsoundRingDistance(csReadPos, pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize);
+        if (csCaptured == 0)
+            break;
+
+        /* Using as an intermediate not circular buffer. */
+        AudioMixBufReset(&pHstStrmIn->MixBuf);
+
+        /* Get number of free samples in the mix buffer and check that is has free space */
+        uint32_t csMixFree = AudioMixBufFree(&pHstStrmIn->MixBuf);
+        if (csMixFree == 0)
+        {
+            DSLOGF(("DSound: Capture buffer full\n"));
+            break;
+        }
+
+        DSLOGF(("DSound: Capture csMixFree=%RU32, csReadPos=%ld, csCaptureReadPos=%ld, csCaptured=%ld\n",
+                csMixFree, csReadPos, pDSoundStrmIn->csCaptureReadPos, csCaptured));
+
+        /* No need to fetch more samples than mix buffer can receive. */
+        csCaptured = RT_MIN(csCaptured, csMixFree);
+
+        /* Lock relevant range in the DirectSound capture buffer. */
+        LPVOID pv1, pv2;
+        DWORD cb1, cb2;
+        hr = directSoundCaptureLock(pDSCB, &pHstStrmIn->Props,
+                                    AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, pDSoundStrmIn->csCaptureReadPos), /* dwOffset */
+                                    AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, csCaptured),                      /* dwBytes */
+                                    &pv1, &pv2, &cb1, &cb2,
+                                    0 /* dwFlags */);
+        if (FAILED(hr))
+        {
+            rc = VERR_ACCESS_DENIED;
+            break;
+        }
+
+        DWORD len1 = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cb1);
+        DWORD len2 = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cb2);
+
+        uint32_t csWrittenTotal = 0;
+        uint32_t csWritten;
+        if (pv1 && len1)
+        {
+            rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, 0 /* offWrite */,
+                                    pv1, cb1, &csWritten);
+            if (RT_SUCCESS(rc))
+                csWrittenTotal += csWritten;
+        }
+
+        if (   RT_SUCCESS(rc)
+            && csWrittenTotal == len1
+            && pv2 && len2)
+        {
+            rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, csWrittenTotal,
+                                    pv2, cb2, &csWritten);
+            if (RT_SUCCESS(rc))
+                csWrittenTotal += csWritten;
+        }
+
+        directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
+
+        if (csWrittenTotal) /* Captured something? */
+            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, csWrittenTotal, &cCaptured);
+
+        if (RT_SUCCESS(rc))
+        {
+            pDSoundStrmIn->csCaptureReadPos = (pDSoundStrmIn->csCaptureReadPos + cCaptured) % pDSoundStrmIn->csCaptureBufferSize;
+            DSLOGF(("DSound: Capture %ld (%ld+%ld), processed %RU32/%RU32\n",
+                    csCaptured, len1, len2, cCaptured, csWrittenTotal));
+        }
+
+    } while (0);
+
+    if (RT_FAILURE(rc))
+    {
+        dsoundUpdateStatusInternal(pThis);
+    }
+    else
+    {
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cCaptured;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostDSoundFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    RT_NOREF(pInterface);
+    PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+
+    directSoundCaptureClose(pDSoundStrmIn);
+
+    pDSoundStrmIn->csCaptureReadPos    = 0;
+    pDSoundStrmIn->csCaptureBufferSize = 0;
+    RT_ZERO(pDSoundStrmIn->streamCfg);
+
+    return VINF_SUCCESS;
+}
+
+/** @todo Replace PDMAUDIODIR with a (registered? unique) channel ID to provide multi-channel input/output. */
+static DECLCALLBACK(bool) drvHostDSoundIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    AssertPtrReturn(pInterface, false);
+
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+    if (enmDir == PDMAUDIODIR_IN)
+        return pThis->fEnabledIn;
+
+    return pThis->fEnabledOut;
+}
+
+static DECLCALLBACK(int) drvHostDSoundGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
+
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+    dsoundUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
+
+    return VINF_SUCCESS;
+}
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    if (fShutdown)
+    {
+        LogFlowFunc(("Shutting down thread ...\n"));
+        pThis->fShutdown = fShutdown;
+    }
+
+    /* Set the notification event so that the thread is being notified. */
+    BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
+    Assert(fRc);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostDSoundThread(RTTHREAD hThreadSelf, void *pvUser)
+{
+    PDRVHOSTDSOUND pThis = (PDRVHOSTDSOUND)pvUser;
+    AssertPtr(pThis);
+
+    LogFlowFuncEnter();
+
+    /* Let caller know that we're done initializing, regardless of the result. */
+    int rc = RTThreadUserSignal(hThreadSelf);
+    AssertRC(rc);
+
+    do
+    {
+        HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS];
+        DWORD  cEvents = 0;
+        for (uint8_t i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++)
+        {
+            if (pThis->aEvents[i])
+                aEvents[cEvents++] = pThis->aEvents[i];
+        }
+        Assert(cEvents);
+
+        LogFlowFunc(("Waiting: cEvents=%ld\n", cEvents));
+
+        DWORD dwObj = WaitForMultipleObjects(cEvents, aEvents, FALSE /* bWaitAll */, INFINITE);
+        switch (dwObj)
+        {
+            case WAIT_FAILED:
+            {
+                rc = VERR_CANCELLED;
+                break;
+            }
+
+            case WAIT_TIMEOUT:
+            {
+                rc = VERR_TIMEOUT;
+                break;
+            }
+
+            default:
+            {
+                dwObj = WAIT_OBJECT_0 + cEvents - 1;
+                if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_NOTIFY])
+                {
+                    LogFlowFunc(("Notify\n"));
+                }
+                else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_INPUT])
+                {
+
+                }
+                else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_OUTPUT])
+                {
+                    DWORD cbBuffer, cbFree, cbPlayPos;
+                    rc = dsoundGetPosOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
+                    if (   RT_SUCCESS(rc)
+                        && cbFree)
+                    {
+                        PDMAUDIOCALLBACKDATAOUT Out;
+                        Out.cbInFree     = cbFree;
+                        Out.cbOutWritten = 0;
+
+                        while (!Out.cbOutWritten)
+                        {
+                            rc = pThis->pUpIAudioConnector->pfnCallback(pThis->pUpIAudioConnector,
+                                                                        PDMAUDIOCALLBACKTYPE_OUTPUT, &Out, sizeof(Out));
+                            if (RT_FAILURE(rc))
+                                break;
+                            RTThreadSleep(100);
+                        }
+
+                        LogFlowFunc(("Output: cbBuffer=%ld, cbFree=%ld, cbPlayPos=%ld, cbWritten=%RU32, rc=%Rrc\n",
+                                     cbBuffer, cbFree, cbPlayPos, Out.cbOutWritten, rc));
+                    }
+                }
+                break;
+            }
+        }
+
+        if (pThis->fShutdown)
+            break;
+
+    } while (RT_SUCCESS(rc));
+
+    pThis->fStopped = true;
+
+    LogFlowFunc(("Exited with fShutdown=%RTbool, rc=%Rrc\n", pThis->fShutdown, rc));
+    return rc;
+}
+#endif /* VBOX_WITH_AUDIO_CALLBACKS */
+
+static DECLCALLBACK(void) drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+    LogFlowFuncEnter();
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    int rc = dsoundNotifyThread(pThis, true /* fShutdown */);
+    AssertRC(rc);
+
+    int rcThread;
+    rc = RTThreadWait(pThis->Thread,  15 * 1000 /* 15s timeout */, &rcThread);
+    LogFlowFunc(("rc=%Rrc, rcThread=%Rrc\n", rc, rcThread));
+
+    Assert(pThis->fStopped);
+
+    if (pThis->aEvents[DSOUNDEVENT_NOTIFY])
+    {
+        CloseHandle(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
+        pThis->aEvents[DSOUNDEVENT_NOTIFY] = NULL;
+    }
+#else
+    RT_NOREF(pThis);
+#endif
+
+    LogFlowFuncLeave();
+}
+
+static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
+{
+    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+    LogFlowFuncEnter();
+
+    int rc;
+
+    /* Verify that IDirectSound is available. */
+    LPDIRECTSOUND pDirectSound = NULL;
+    HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_ALL,
+                                  IID_IDirectSound, (void **)&pDirectSound);
+    if (SUCCEEDED(hr))
+    {
+        IDirectSound_Release(pDirectSound);
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+        /* Create notification event. */
+        pThis->aEvents[DSOUNDEVENT_NOTIFY] = CreateEvent(NULL /* Security attribute */,
+                                                         FALSE /* bManualReset */, FALSE /* bInitialState */,
+                                                         NULL /* lpName */);
+        Assert(pThis->aEvents[DSOUNDEVENT_NOTIFY] != NULL);
+
+        /* Start notification thread. */
+        rc = RTThreadCreate(&pThis->Thread, drvHostDSoundThread,
+                            pThis /*pvUser*/, 0 /*cbStack*/,
+                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dSoundNtfy");
+        if (RT_SUCCESS(rc))
+        {
+            /* Wait for the thread to initialize. */
+            rc = RTThreadUserWait(pThis->Thread, RT_MS_1MIN);
+            if (RT_FAILURE(rc))
+                DSLOGREL(("DSound: Waiting for thread to initialize failed with rc=%Rrc\n", rc));
+        }
+    else
+            DSLOGREL(("DSound: Creating thread failed with rc=%Rrc\n", rc));
+#else
+        rc = VINF_SUCCESS;
+#endif
+
+        PDMAUDIOBACKENDCFG Cfg;
+        dsoundUpdateStatusInternalEx(pThis, &Cfg, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
+
+        DSLOGREL(("DSound: Found %RU32 host playback devices\n",  Cfg.cMaxHstStrmsOut));
+        DSLOGREL(("DSound: Found %RU32 host capturing devices\n", Cfg.cMaxHstStrmsIn));
+    }
+    else
+    {
+        DSLOGREL(("DSound: DirectSound not available: %Rhrc\n", hr));
+        rc = VERR_NOT_SUPPORTED;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS     pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTDSOUND pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+    return NULL;
+}
+
+static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID *pUuid)
+{
+    LPCGUID pGuid = NULL;
+
+    char *pszGuid = NULL;
+    int rc = CFGMR3QueryStringAlloc(pCfg, pszName, &pszGuid);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTUuidFromStr(pUuid, pszGuid);
+        if (RT_SUCCESS(rc))
+            pGuid = (LPCGUID)&pUuid;
+        else
+            DSLOGREL(("DSound: Error parsing device GUID for device '%s': %Rrc\n", pszName, rc));
+
+        RTStrFree(pszGuid);
+    }
+
+    return pGuid;
+}
+
+static void dSoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
+{
+    unsigned int uBufsizeOut, uBufsizeIn;
+
+    CFGMR3QueryUIntDef(pCfg, "BufsizeOut", &uBufsizeOut, _16K);
+    CFGMR3QueryUIntDef(pCfg, "BufsizeIn",  &uBufsizeIn,  _16K);
+    pThis->cfg.cbBufferOut = uBufsizeOut;
+    pThis->cfg.cbBufferIn  = uBufsizeIn;
+
+    pThis->cfg.pGuidPlay    = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->cfg.uuidPlay);
+    pThis->cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn",  &pThis->cfg.uuidCapture);
+
+    DSLOG(("DSound: BufsizeOut %u, BufsizeIn %u, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n",
+           pThis->cfg.cbBufferOut,
+           pThis->cfg.cbBufferIn,
+           &pThis->cfg.uuidPlay,
+           &pThis->cfg.uuidCapture));
+}
+
+static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
+{
+    PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+    LogFlowFuncEnter();
+
+    if (pThis->pDrvIns)
+        CoUninitialize();
+
+    LogFlowFuncLeave();
+}
+
+/**
+ * Construct a DirectSound Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(fFlags);
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+    PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
+
+    LogRel(("Audio: Initializing DirectSound audio driver\n"));
+
+
+    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    if (FAILED(hr))
+    {
+        DSLOGREL(("DSound: CoInitializeEx failed with %Rhrc\n", hr));
+        return VERR_NOT_SUPPORTED;
+    }
+
+    /*
+     * Init basic data members and interfaces.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostDSoundQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostDSound);
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    /*
+     * Get the IAudioConnector interface of the above driver/device.
+     */
+    pThis->pUpIAudioConnector = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
+    if (!pThis->pUpIAudioConnector)
+    {
+        AssertMsgFailed(("Configuration error: No audio connector interface above!\n"));
+        return VERR_PDM_MISSING_INTERFACE_ABOVE;
+    }
+#endif
+
+    /*
+     * Init the static parts.
+     */
+    RTListInit(&pThis->lstDevInput);
+    RTListInit(&pThis->lstDevOutput);
+
+    pThis->fEnabledIn  = false;
+    pThis->fEnabledOut = false;
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    pThis->fStopped    = false;
+    pThis->fShutdown   = false;
+
+    RT_ZERO(pThis->aEvents);
+    pThis->cEvents = 0;
+#endif
+
+    /*
+     * Initialize configuration values.
+     */
+    dSoundConfigInit(pThis, pCfg);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * PDM driver registration.
+ */
+const PDMDRVREG g_DrvHostDSound =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "DSoundAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "DirectSound Audio host driver",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTDSOUND),
+    /* pfnConstruct */
+    drvHostDSoundConstruct,
+    /* pfnDestruct */
+    drvHostDSoundDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
diff --git a/src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp
new file mode 100644
index 0000000..a91d7db
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp
@@ -0,0 +1,342 @@
+/* $Id: DrvHostNullAudio.cpp $ */
+/** @file
+ * NULL audio driver -- also acts as a fallback if no
+ * other backend is available.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on: noaudio.c QEMU based code.
+ *
+ * QEMU Timer based audio emulation
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+#include "VBoxDD.h"
+
+#include <iprt/alloc.h>
+#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
+#include <VBox/vmm/pdmaudioifs.h>
+
+typedef struct NULLAUDIOSTREAMOUT
+{
+    /** Note: Always must come first! */
+    PDMAUDIOHSTSTRMOUT streamOut;
+    uint64_t           u64TicksLast;
+    uint64_t           csPlayBuffer;
+    uint8_t           *pu8PlayBuffer;
+} NULLAUDIOSTREAMOUT, *PNULLAUDIOSTREAMOUT;
+
+typedef struct NULLAUDIOSTREAMIN
+{
+    /** Note: Always must come first! */
+    PDMAUDIOHSTSTRMIN  streamIn;
+} NULLAUDIOSTREAMIN, *PNULLAUDIOSTREAMIN;
+
+/**
+ * NULL audio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTNULLAUDIO
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS    pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO IHostAudio;
+} DRVHOSTNULLAUDIO, *PDRVHOSTNULLAUDIO;
+
+/*******************************************PDM_AUDIO_DRIVER******************************/
+
+
+static DECLCALLBACK(int) drvHostNullAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    pCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
+    pCfg->cbStreamIn  = sizeof(NULLAUDIOSTREAMIN);
+
+    pCfg->cMaxHstStrmsOut = 1; /* Output */
+    pCfg->cMaxHstStrmsIn  = 2; /* Line input + microphone input. */
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioInit(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioInitIn(PPDMIHOSTAUDIO pInterface,
+                                                PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
+{
+    NOREF(pInterface);
+    NOREF(enmRecSource);
+    NOREF(pCfgAcq);
+
+    /* Just adopt the wanted stream configuration. */
+    int rc = DrvAudioStreamCfgToProps(pCfgReq, &pHstStrmIn->Props);
+    if (RT_SUCCESS(rc))
+    {
+        if (pcSamples)
+            *pcSamples = _1K;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioInitOut(PPDMIHOSTAUDIO pInterface,
+                                                 PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                 uint32_t *pcSamples)
+{
+    NOREF(pInterface);
+    NOREF(pCfgAcq);
+
+    /* Just adopt the wanted stream configuration. */
+    int rc = DrvAudioStreamCfgToProps(pCfgReq, &pHstStrmOut->Props);
+    if (RT_SUCCESS(rc))
+    {
+        PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
+        pNullStrmOut->u64TicksLast  = 0;
+        pNullStrmOut->csPlayBuffer  = _1K;
+        pNullStrmOut->pu8PlayBuffer = (uint8_t *)RTMemAlloc(_1K << pHstStrmOut->Props.cShift);
+        if (pNullStrmOut->pu8PlayBuffer)
+        {
+            if (pcSamples)
+                *pcSamples = pNullStrmOut->csPlayBuffer;
+        }
+        else
+        {
+            rc = VERR_NO_MEMORY;
+        }
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvHostNullAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    NOREF(pInterface);
+    NOREF(enmDir);
+    return true; /* Always all enabled. */
+}
+
+static DECLCALLBACK(int) drvHostNullAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                 uint32_t *pcSamplesPlayed)
+{
+    PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
+    PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
+
+    /* Consume as many samples as would be played at the current frequency since last call. */
+    uint32_t csLive          = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+    uint64_t u64TicksNow     = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
+    uint64_t u64TicksElapsed = u64TicksNow  - pNullStrmOut->u64TicksLast;
+    uint64_t u64TicksFreq    = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
+
+    /* Remember when samples were consumed. */
+    pNullStrmOut->u64TicksLast = u64TicksNow;
+
+    /*
+     * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
+     * If rounding is not taken into account then the playback rate will be consistently lower that expected.
+     */
+    uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pHstStrmOut->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
+
+    /* Don't play more than available. */
+    if (cSamplesPlayed > csLive)
+        cSamplesPlayed = csLive;
+
+    cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStrmOut->csPlayBuffer);
+
+    uint32_t csRead = 0;
+    AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pNullStrmOut->pu8PlayBuffer,
+                        AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cSamplesPlayed), &csRead);
+    AudioMixBufFinish(&pHstStrmOut->MixBuf, csRead);
+
+    if (pcSamplesPlayed)
+        *pcSamplesPlayed = csRead;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   uint32_t *pcSamplesCaptured)
+{
+    RT_NOREF(pInterface, pHstStrmIn);
+    /* Never capture anything. */
+    if (pcSamplesCaptured)
+        *pcSamplesCaptured = 0;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    NOREF(pHstStrmIn);
+    NOREF(enmStreamCmd);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                    PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    NOREF(pHstStrmOut);
+    NOREF(enmStreamCmd);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    RT_NOREF(pInterface, pHstStrmIn);
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostNullAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    RT_NOREF(pInterface);
+    PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
+    if (   pNullStrmOut
+        && pNullStrmOut->pu8PlayBuffer)
+    {
+        RTMemFree(pNullStrmOut->pu8PlayBuffer);
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS        pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTNULLAUDIO pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+    return NULL;
+}
+
+static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+}
+
+/**
+ * Constructs a Null audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(pCfg, fFlags);
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+
+    PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
+    LogRel(("Audio: Initializing NULL driver\n"));
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Char driver registration record.
+ */
+const PDMDRVREG g_DrvHostNullAudio =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "NullAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "NULL audio host driver",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTNULLAUDIO),
+    /* pfnConstruct */
+    drvHostNullAudioConstruct,
+    /* pfnDestruct */
+    NULL,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
diff --git a/src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp
new file mode 100644
index 0000000..098df56
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp
@@ -0,0 +1,1006 @@
+/* $Id: DrvHostOSSAudio.cpp $ */
+/** @file
+ * OSS (Open Sound System) host audio backend.
+ */
+
+/*
+ * Copyright (C) 2014-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ */
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+#include "VBoxDD.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/soundcard.h>
+#include <unistd.h>
+
+#include <iprt/alloc.h>
+#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
+#include <VBox/vmm/pdmaudioifs.h>
+
+/**
+ * OSS host audio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTOSSAUDIO
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS         pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO      IHostAudio;
+    /** Error count for not flooding the release log.
+     *  UINT32_MAX for unlimited logging. */
+    uint32_t           cLogErrors;
+} DRVHOSTOSSAUDIO, *PDRVHOSTOSSAUDIO;
+
+typedef struct OSSAUDIOSTREAMCFG
+{
+    PDMAUDIOFMT       enmFormat;
+    PDMAUDIOENDIANNESS enmENDIANNESS;
+    uint16_t          uFreq;
+    uint8_t           cChannels;
+    uint16_t          cFragments;
+    uint32_t          cbFragmentSize;
+} OSSAUDIOSTREAMCFG, *POSSAUDIOSTREAMCFG;
+
+typedef struct OSSAUDIOSTREAMIN
+{
+    /** Note: Always must come first! */
+    PDMAUDIOHSTSTRMIN  pStreamIn;
+    int                hFile;
+    int                cFragments;
+    int                cbFragmentSize;
+    /** Own PCM buffer. */
+    void              *pvPCMBuf;
+    /** Size (in bytes) of own PCM buffer. */
+    size_t             cbPCMBuf;
+    int                old_optr;
+} OSSAUDIOSTREAMIN, *POSSAUDIOSTREAMIN;
+
+typedef struct OSSAUDIOSTREAMOUT
+{
+    /** Note: Always must come first! */
+    PDMAUDIOHSTSTRMOUT  pStreamOut;
+    int                 hFile;
+    int                 cFragments;
+    int                 cbFragmentSize;
+#ifndef RT_OS_L4
+    /** Whether we use a memory mapped file instead of our
+     *  own allocated PCM buffer below. */
+    bool                fMemMapped;
+#endif
+    /** Own PCM buffer in case memory mapping is unavailable. */
+    void               *pvPCMBuf;
+    /** Size (in bytes) of own PCM buffer. */
+    size_t              cbPCMBuf;
+    int                 old_optr;
+} OSSAUDIOSTREAMOUT, *POSSAUDIOSTREAMOUT;
+
+typedef struct OSSAUDIOCFG
+{
+#ifndef RT_OS_L4
+    bool try_mmap;
+#endif
+    int nfrags;
+    int fragsize;
+    const char *devpath_out;
+    const char *devpath_in;
+    int debug;
+} OSSAUDIOCFG, *POSSAUDIOCFG;
+
+static OSSAUDIOCFG s_OSSConf =
+{
+#ifndef RT_OS_L4
+    false,
+#endif
+    4,
+    4096,
+    "/dev/dsp",
+    "/dev/dsp",
+    0
+};
+
+
+/* http://www.df.lth.se/~john_e/gems/gem002d.html */
+static uint32_t popcount(uint32_t u)
+{
+    u = ((u&0x55555555) + ((u>>1)&0x55555555));
+    u = ((u&0x33333333) + ((u>>2)&0x33333333));
+    u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
+    u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
+    u = ( u&0x0000ffff) + (u>>16);
+    return u;
+}
+
+static uint32_t lsbindex(uint32_t u)
+{
+    return popcount ((u&-u)-1);
+}
+
+static int drvHostOSSAudioFmtToOSS(PDMAUDIOFMT fmt)
+{
+    switch (fmt)
+    {
+        case AUD_FMT_S8:
+            return AFMT_S8;
+
+        case AUD_FMT_U8:
+            return AFMT_U8;
+
+        case AUD_FMT_S16:
+            return AFMT_S16_LE;
+
+        case AUD_FMT_U16:
+            return AFMT_U16_LE;
+
+        default:
+            break;
+    }
+
+    AssertMsgFailed(("Format %ld not supported\n", fmt));
+    return AFMT_U8;
+}
+
+static int drvHostOSSAudioOSSToFmt(int fmt,
+                                   PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pENDIANNESS)
+{
+    switch (fmt)
+    {
+        case AFMT_S8:
+            *pFmt = AUD_FMT_S8;
+            if (pENDIANNESS)
+                *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case AFMT_U8:
+            *pFmt = AUD_FMT_U8;
+            if (pENDIANNESS)
+                *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case AFMT_S16_LE:
+            *pFmt = AUD_FMT_S16;
+            if (pENDIANNESS)
+                *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case AFMT_U16_LE:
+            *pFmt = AUD_FMT_U16;
+            if (pENDIANNESS)
+                *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case AFMT_S16_BE:
+            *pFmt = AUD_FMT_S16;
+            if (pENDIANNESS)
+                *pENDIANNESS = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+        case AFMT_U16_BE:
+            *pFmt = AUD_FMT_U16;
+            if (pENDIANNESS)
+                *pENDIANNESS = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+        default:
+            AssertMsgFailed(("Format %ld not supported\n", fmt));
+            return VERR_NOT_SUPPORTED;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int drvHostOSSAudioClose(int *phFile)
+{
+    if (!phFile || !*phFile)
+        return VINF_SUCCESS;
+
+    int rc;
+    if (close(*phFile))
+    {
+        LogRel(("OSS: Closing descriptor failed: %s\n",
+                strerror(errno)));
+        rc = VERR_GENERAL_FAILURE; /** @todo */
+    }
+    else
+    {
+        *phFile = -1;
+        rc = VINF_SUCCESS;
+    }
+
+    return rc;
+}
+
+static int drvHostOSSAudioOpen(bool fIn,
+                               POSSAUDIOSTREAMCFG pReq, POSSAUDIOSTREAMCFG pObt,
+                               int *phFile)
+{
+    AssertPtrReturn(pReq, VERR_INVALID_POINTER);
+    AssertPtrReturn(pObt, VERR_INVALID_POINTER);
+    AssertPtrReturn(phFile, VERR_INVALID_POINTER);
+
+    int rc;
+    int hFile;
+
+    do
+    {
+        const char *pszDev = fIn ? s_OSSConf.devpath_in : s_OSSConf.devpath_out;
+        if (!pszDev)
+        {
+            LogRel(("OSS: Invalid or no %s device name set\n",
+                    fIn ? "input" : "output"));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+        }
+
+        hFile = open(pszDev, (fIn ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
+        if (hFile == -1)
+        {
+            LogRel(("OSS: Failed to open %s: %s(%d)\n", pszDev, strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+
+        int iFormat = drvHostOSSAudioFmtToOSS(pReq->enmFormat);
+        if (ioctl(hFile, SNDCTL_DSP_SAMPLESIZE, &iFormat))
+        {
+            LogRel(("OSS: Failed to set audio format to %ld errno=%s(%d)\n", iFormat, strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+
+        int cChannels = pReq->cChannels;
+        if (ioctl(hFile, SNDCTL_DSP_CHANNELS, &cChannels))
+        {
+            LogRel(("OSS: Failed to set number of audio channels (%d): %s(%d)\n", pReq->cChannels, strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+
+        int freq = pReq->uFreq;
+        if (ioctl(hFile, SNDCTL_DSP_SPEED, &freq))
+        {
+            LogRel(("OSS: Failed to set audio frequency (%dHZ): %s(%d)\n", pReq->uFreq, strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+
+        /* Obsolete on Solaris (using O_NONBLOCK is sufficient). */
+#if !(defined(VBOX) && defined(RT_OS_SOLARIS))
+        if (ioctl(hFile, SNDCTL_DSP_NONBLOCK))
+        {
+            LogRel(("OSS: Failed to set non-blocking mode: %s(%d)\n", strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+#endif
+        int mmmmssss = (pReq->cFragments << 16) | lsbindex(pReq->cbFragmentSize);
+        if (ioctl(hFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss))
+        {
+            LogRel(("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s(%d)\n",
+                    pReq->cFragments, pReq->cbFragmentSize, strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+
+        audio_buf_info abinfo;
+        if (ioctl(hFile, fIn ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo))
+        {
+            LogRel(("OSS: Failed to retrieve buffer length: %s(%d)\n", strerror(errno), errno));
+            rc = RTErrConvertFromErrno(errno);
+            break;
+        }
+
+        rc = drvHostOSSAudioOSSToFmt(iFormat, &pObt->enmFormat, &pObt->enmENDIANNESS);
+        if (RT_SUCCESS(rc))
+        {
+            pObt->cChannels      = cChannels;
+            pObt->uFreq          = freq;
+            pObt->cFragments     = abinfo.fragstotal;
+            pObt->cbFragmentSize = abinfo.fragsize;
+
+            *phFile = hFile;
+        }
+    }
+    while (0);
+
+    if (RT_FAILURE(rc))
+        drvHostOSSAudioClose(&hFile);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                   PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    NOREF(pHstStrmIn);
+    NOREF(enmStreamCmd);
+
+    /** @todo Nothing to do here right now!? */
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                   PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
+
+#ifdef RT_OS_L4
+    return VINF_SUCCESS;
+#else
+    if (!pThisStrmOut->fMemMapped)
+        return VINF_SUCCESS;
+#endif
+
+    int rc = VINF_SUCCESS;
+    int mask;
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            DrvAudioClearBuf(&pHstStrmOut->Props,
+                             pThisStrmOut->pvPCMBuf, pThisStrmOut->cbPCMBuf, AudioMixBufSize(&pHstStrmOut->MixBuf));
+
+            mask = PCM_ENABLE_OUTPUT;
+            if (ioctl(pThisStrmOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
+            {
+                LogRel(("OSS: Failed to enable output stream: %s\n", strerror(errno)));
+                rc = RTErrConvertFromErrno(errno);
+            }
+
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            mask = 0;
+            if (ioctl(pThisStrmOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
+            {
+                LogRel(("OSS: Failed to disable output stream: %s\n", strerror(errno)));
+                rc = RTErrConvertFromErrno(errno);
+            }
+
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioInit(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                  uint32_t *pcSamplesCaptured)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
+
+    int rc = VINF_SUCCESS;
+    size_t cbToRead = RT_MIN(pThisStrmIn->cbPCMBuf,
+                             AudioMixBufFreeBytes(&pHstStrmIn->MixBuf));
+
+    LogFlowFunc(("cbToRead=%zu\n", cbToRead));
+
+    uint32_t cWrittenTotal = 0;
+    uint32_t cbTemp;
+    ssize_t  cbRead;
+    size_t   offWrite = 0;
+
+    while (cbToRead)
+    {
+        cbTemp = RT_MIN(cbToRead, pThisStrmIn->cbPCMBuf);
+        AssertBreakStmt(cbTemp, rc = VERR_NO_DATA);
+        cbRead = read(pThisStrmIn->hFile, (uint8_t *)pThisStrmIn->pvPCMBuf + offWrite, cbTemp);
+
+        LogFlowFunc(("cbRead=%zi, cbTemp=%RU32, cbToRead=%zu\n",
+                     cbRead, cbTemp, cbToRead));
+
+        if (cbRead < 0)
+        {
+            switch (errno)
+            {
+                case 0:
+                {
+                    LogFunc(("Failed to read %z frames\n", cbRead));
+                    rc = VERR_ACCESS_DENIED;
+                    break;
+                }
+
+                case EINTR:
+                case EAGAIN:
+                    rc = VERR_NO_DATA;
+                    break;
+
+                default:
+                    LogFlowFunc(("Failed to read %zu input frames, rc=%Rrc\n",
+                                 cbTemp, rc));
+                    rc = VERR_GENERAL_FAILURE; /** @todo */
+                    break;
+            }
+
+            if (RT_FAILURE(rc))
+                break;
+        }
+        else if (cbRead)
+        {
+            uint32_t cWritten;
+            rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
+                                      pThisStrmIn->pvPCMBuf, cbRead,
+                                      &cWritten);
+            if (RT_FAILURE(rc))
+                break;
+
+            uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
+
+            Assert(cbToRead >= cbWritten);
+            cbToRead      -= cbWritten;
+            offWrite      += cbWritten;
+            cWrittenTotal += cWritten;
+        }
+        else /* No more data, try next round. */
+            break;
+    }
+
+    if (rc == VERR_NO_DATA)
+        rc = VINF_SUCCESS;
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cProcessed = 0;
+        if (cWrittenTotal)
+            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
+                                        &cProcessed);
+
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cWrittenTotal;
+
+        LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
+                     cWrittenTotal, cProcessed, rc));
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
+
+    LogFlowFuncEnter();
+
+    if (pThisStrmIn->pvPCMBuf)
+    {
+        Assert(pThisStrmIn->cbPCMBuf);
+
+        RTMemFree(pThisStrmIn->pvPCMBuf);
+        pThisStrmIn->pvPCMBuf = NULL;
+    }
+
+    pThisStrmIn->cbPCMBuf = 0;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
+
+    LogFlowFuncEnter();
+
+#ifndef RT_OS_L4
+    if (!pThisStrmOut->fMemMapped)
+    {
+        if (pThisStrmOut->pvPCMBuf)
+        {
+            Assert(pThisStrmOut->cbPCMBuf);
+
+            RTMemFree(pThisStrmOut->pvPCMBuf);
+            pThisStrmOut->pvPCMBuf = NULL;
+        }
+
+        pThisStrmOut->cbPCMBuf = 0;
+    }
+#endif
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    NOREF(pInterface);
+
+    pCfg->cbStreamOut = sizeof(OSSAUDIOSTREAMOUT);
+    pCfg->cbStreamIn = sizeof(OSSAUDIOSTREAMIN);
+    pCfg->cMaxHstStrmsOut = INT_MAX;
+    pCfg->cMaxHstStrmsIn = INT_MAX;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioInitIn(PPDMIHOSTAUDIO pInterface,
+                                               PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                               PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                               PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
+{
+    RT_NOREF(pInterface, pCfgAcq, enmRecSource);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
+
+    int rc;
+    int hFile = -1;
+
+    do
+    {
+        uint32_t cSamples;
+
+        OSSAUDIOSTREAMCFG reqStream, obtStream;
+        reqStream.enmFormat      = pCfgReq->enmFormat;
+        reqStream.uFreq          = pCfgReq->uHz;
+        reqStream.cChannels      = pCfgReq->cChannels;
+        reqStream.cFragments     = s_OSSConf.nfrags;
+        reqStream.cbFragmentSize = s_OSSConf.fragsize;
+
+        rc = drvHostOSSAudioOpen(true /* fIn */,
+                                 &reqStream, &obtStream, &hFile);
+        if (RT_SUCCESS(rc))
+        {
+            if (obtStream.cFragments * obtStream.cbFragmentSize & pHstStrmIn->Props.uAlign)
+                LogRel(("OSS: Warning: Misaligned DAC output buffer: Size = %zu, Alignment = %u\n",
+                        obtStream.cFragments * obtStream.cbFragmentSize,
+                        pHstStrmIn->Props.uAlign + 1));
+
+            pThisStrmIn->hFile = hFile;
+
+            PDMAUDIOSTREAMCFG streamCfg;
+            streamCfg.enmFormat     = obtStream.enmFormat;
+            streamCfg.uHz           = obtStream.uFreq;
+            streamCfg.cChannels     = pCfgReq->cChannels;
+            streamCfg.enmEndianness = obtStream.enmENDIANNESS;
+
+            rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
+            if (RT_SUCCESS(rc))
+            {
+                cSamples = (obtStream.cFragments * obtStream.cbFragmentSize)
+                           >> pHstStrmIn->Props.cShift;
+                if (!cSamples)
+                    rc = VERR_INVALID_PARAMETER;
+            }
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            size_t cbSample = (1 << pHstStrmIn->Props.cShift);
+            size_t cbBuf    = cSamples * cbSample;
+            pThisStrmIn->pvPCMBuf = RTMemAlloc(cbBuf);
+            if (!pThisStrmIn->pvPCMBuf)
+            {
+                LogRel(("OSS: Failed allocating ADC buffer with %RU32 samples (%zu bytes per sample)\n", cSamples, cbSample));
+                rc = VERR_NO_MEMORY;
+            }
+
+            pThisStrmIn->cbPCMBuf = cbBuf;
+
+            if (pcSamples)
+                *pcSamples = cSamples;
+        }
+
+    } while (0);
+
+    if (RT_FAILURE(rc))
+        drvHostOSSAudioClose(&hFile);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioInitOut(PPDMIHOSTAUDIO pInterface,
+                                                PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                uint32_t *pcSamples)
+{
+    RT_NOREF(pInterface, pCfgAcq);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,     VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
+
+    int rc;
+    int hFile = -1;
+
+    do
+    {
+        uint32_t cSamples;
+
+        OSSAUDIOSTREAMCFG reqStream, obtStream;
+        reqStream.enmFormat      = pCfgReq->enmFormat;
+        reqStream.uFreq          = pCfgReq->uHz;
+        reqStream.cChannels      = pCfgReq->cChannels;
+        reqStream.cFragments     = s_OSSConf.nfrags;
+        reqStream.cbFragmentSize = s_OSSConf.fragsize;
+
+        rc = drvHostOSSAudioOpen(false /* fIn */,
+                                 &reqStream, &obtStream, &hFile);
+        if (RT_SUCCESS(rc))
+        {
+            if (obtStream.cFragments * obtStream.cbFragmentSize & pHstStrmOut->Props.uAlign)
+                LogRel(("OSS: Warning: Misaligned DAC output buffer: Size = %zu, Alignment = %u\n",
+                        obtStream.cFragments * obtStream.cbFragmentSize,
+                        pHstStrmOut->Props.uAlign + 1));
+
+            pThisStrmOut->hFile = hFile;
+
+            PDMAUDIOSTREAMCFG streamCfg;
+            streamCfg.enmFormat     = obtStream.enmFormat;
+            streamCfg.uHz           = obtStream.uFreq;
+            streamCfg.cChannels     = pCfgReq->cChannels;
+            streamCfg.enmEndianness = obtStream.enmENDIANNESS;
+
+            rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
+            if (RT_SUCCESS(rc))
+                cSamples = (obtStream.cFragments * obtStream.cbFragmentSize)
+                           >> pHstStrmOut->Props.cShift;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+#ifndef RT_OS_L4
+            pThisStrmOut->fMemMapped = false;
+            if (s_OSSConf.try_mmap)
+            {
+                pThisStrmOut->pvPCMBuf = mmap(0, cSamples << pHstStrmOut->Props.cShift,
+                                              PROT_READ | PROT_WRITE, MAP_SHARED, hFile, 0);
+                if (pThisStrmOut->pvPCMBuf == MAP_FAILED)
+                {
+                    LogRel(("OSS: Failed to memory map %zu bytes of DAC output file: %s\n",
+                            cSamples << pHstStrmOut->Props.cShift, strerror(errno)));
+                    rc = RTErrConvertFromErrno(errno);
+                    break;
+                }
+                else
+                {
+                    int mask = 0;
+                    if (ioctl(hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
+                    {
+                        LogRel(("OSS: Failed to retrieve initial trigger mask: %s\n",
+                                strerror(errno)));
+                        rc = RTErrConvertFromErrno(errno);
+                        /* Note: No break here, need to unmap file first! */
+                    }
+                    else
+                    {
+                        mask = PCM_ENABLE_OUTPUT;
+                        if (ioctl (hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
+                        {
+                            LogRel(("OSS: Failed to retrieve PCM_ENABLE_OUTPUT mask: %s\n",
+                                    strerror(errno)));
+                            rc = RTErrConvertFromErrno(errno);
+                            /* Note: No break here, need to unmap file first! */
+                        }
+                        else
+                            pThisStrmOut->fMemMapped = true;
+                    }
+
+                    if (!pThisStrmOut->fMemMapped)
+                    {
+                        int rc2 = munmap(pThisStrmOut->pvPCMBuf,
+                                         cSamples << pHstStrmOut->Props.cShift);
+                        if (rc2)
+                            LogRel(("OSS: Failed to unmap DAC output file: %s\n", strerror(errno)));
+                        break;
+                    }
+                }
+            }
+#endif /* !RT_OS_L4 */
+
+            /* Memory mapping failed above? Try allocating an own buffer. */
+#ifndef RT_OS_L4
+            if (!pThisStrmOut->fMemMapped)
+            {
+#endif
+                size_t cbSample = (1 << pHstStrmOut->Props.cShift);
+                size_t cbPCMBuf = cSamples * cbSample;
+
+                LogFlowFunc(("cSamples=%RU32\n", cSamples));
+
+                pThisStrmOut->pvPCMBuf = RTMemAlloc(cbPCMBuf);
+                if (!pThisStrmOut->pvPCMBuf)
+                {
+                    LogRel(("OSS: Failed allocating DAC buffer with %RU32 samples (%zu bytes per sample)\n", cSamples, cbSample));
+                    rc = VERR_NO_MEMORY;
+                    break;
+                }
+
+                pThisStrmOut->cbPCMBuf = cbPCMBuf;
+#ifndef RT_OS_L4
+            }
+#endif
+            if (pcSamples)
+                *pcSamples = cSamples;
+        }
+
+    } while (0);
+
+    if (RT_FAILURE(rc))
+        drvHostOSSAudioClose(&hFile);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvHostOSSAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    NOREF(pInterface);
+    NOREF(enmDir);
+    return true; /* Always all enabled. */
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                uint32_t *pcSamplesPlayed)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
+
+    int rc = VINF_SUCCESS;
+    uint32_t cbReadTotal = 0;
+    count_info cntinfo;
+
+    do
+    {
+        size_t cbBuf = AudioMixBufSizeBytes(&pHstStrmOut->MixBuf);
+
+        uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+        uint32_t cToRead;
+
+#ifndef RT_OS_L4
+        if (pThisStrmOut->fMemMapped)
+        {
+            /* Get current playback pointer. */
+            int rc2 = ioctl(pThisStrmOut->hFile, SNDCTL_DSP_GETOPTR, &cntinfo);
+            if (!rc2)
+            {
+                LogRel(("OSS: Failed to retrieve current playback pointer: %s\n",
+                        strerror(errno)));
+                rc = RTErrConvertFromErrno(errno);
+                break;
+            }
+
+            /* Nothing to play? */
+            if (cntinfo.ptr == pThisStrmOut->old_optr)
+                break;
+
+            int cbData;
+            if (cntinfo.ptr > pThisStrmOut->old_optr)
+                cbData = cntinfo.ptr - pThisStrmOut->old_optr;
+            else
+                cbData = cbBuf + cntinfo.ptr - pThisStrmOut->old_optr;
+            Assert(cbData);
+
+            cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbData),
+                             cLive);
+        }
+        else
+        {
+#endif
+            audio_buf_info abinfo;
+            int rc2 = ioctl(pThisStrmOut->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
+            if (rc2 < 0)
+            {
+                LogRel(("OSS: Failed to retrieve current playback buffer: %s\n",
+                        strerror(errno)));
+                rc = RTErrConvertFromErrno(errno);
+                break;
+            }
+
+            if ((size_t)abinfo.bytes > cbBuf)
+            {
+                LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%d\n",
+                             abinfo.bytes, cbBuf));
+                abinfo.bytes = cbBuf;
+                /* Keep going. */
+            }
+
+            if (abinfo.bytes < 0)
+            {
+                LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%d\n",
+                             abinfo.bytes, cbBuf));
+                rc = VERR_INVALID_PARAMETER;
+                break;
+            }
+
+            cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, abinfo.bytes),
+                             cLive);
+            if (!cToRead)
+                break;
+#ifndef RT_OS_L4
+        }
+#endif
+        size_t cbToRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cToRead);
+        LogFlowFunc(("cbToRead=%zu\n", cbToRead));
+
+        uint32_t cRead, cbRead;
+        while (cbToRead)
+        {
+            rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf,
+                                     pThisStrmOut->pvPCMBuf, cbToRead, &cRead);
+            if (RT_FAILURE(rc))
+                break;
+
+            cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
+            ssize_t cbWritten = write(pThisStrmOut->hFile, pThisStrmOut->pvPCMBuf,
+                                      cbRead);
+            if (cbWritten == -1)
+            {
+                LogRel(("OSS: Failed writing output data: %s\n", strerror(errno)));
+                rc = RTErrConvertFromErrno(errno);
+                break;
+            }
+
+            Assert(cbToRead >= cbRead);
+            cbToRead -= cbRead;
+            cbReadTotal += cbRead;
+        }
+
+#ifndef RT_OS_L4
+        /* Update read pointer. */
+        if (pThisStrmOut->fMemMapped)
+            pThisStrmOut->old_optr = cntinfo.ptr;
+#endif
+
+    } while(0);
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
+        if (cReadTotal)
+            AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
+
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = cReadTotal;
+
+        LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
+                     cReadTotal, cbReadTotal, rc));
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(void) drvHostOSSAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvHostOSSAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTOSSAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+
+    return NULL;
+}
+
+/**
+ * Constructs an OSS audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostOSSAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(pCfg, fFlags);
+    PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
+    LogRel(("Audio: Initializing OSS driver\n"));
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostOSSAudioQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostOSSAudio);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Char driver registration record.
+ */
+const PDMDRVREG g_DrvHostOSSAudio =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "OSSAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "OSS audio host driver",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTOSSAUDIO),
+    /* pfnConstruct */
+    drvHostOSSAudioConstruct,
+    /* pfnDestruct */
+    NULL,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
diff --git a/src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp
new file mode 100644
index 0000000..951ab17
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp
@@ -0,0 +1,1257 @@
+/* $Id: DrvHostPulseAudio.cpp $ */
+/** @file
+ * VBox audio devices: Pulse Audio audio driver.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+
+#include <stdio.h>
+
+#include <iprt/alloc.h>
+#include <iprt/mem.h>
+#include <iprt/uuid.h>
+
+RT_C_DECLS_BEGIN
+ #include "pulse_mangling.h"
+ #include "pulse_stubs.h"
+RT_C_DECLS_END
+
+#include <pulse/pulseaudio.h>
+
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+#include "VBoxDD.h"
+
+#define VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS 32 /** @todo Make this configurable thru driver options. */
+
+#ifndef PA_STREAM_NOFLAGS
+# define PA_STREAM_NOFLAGS (pa_context_flags_t)0x0000U /* since 0.9.19 */
+#endif
+
+#ifndef PA_CONTEXT_NOFLAGS
+# define PA_CONTEXT_NOFLAGS (pa_context_flags_t)0x0000U /* since 0.9.19 */
+#endif
+
+/*
+ * We use a g_pMainLoop in a separate thread g_pContext. We have to call functions for
+ * manipulating objects either from callback functions or we have to protect
+ * these functions by pa_threaded_mainloop_lock() / pa_threaded_mainloop_unlock().
+ */
+static struct pa_threaded_mainloop *g_pMainLoop;
+static struct pa_context           *g_pContext;
+static volatile bool                g_fAbortMainLoop;
+
+/**
+ * Host Pulse audio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTPULSEAUDIO
+{
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS         pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO      IHostAudio;
+    /** Error count for not flooding the release log.
+     *  UINT32_MAX for unlimited logging. */
+    uint32_t           cLogErrors;
+    /** Configuration option: stream name. */
+    char               *pszStreamName;
+} DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO;
+
+typedef struct PULSEAUDIOSTREAM
+{
+    /** Must come first, as this struct might be
+     *  casted to one of these structs. */
+    union
+    {
+        PDMAUDIOHSTSTRMIN  In;
+        PDMAUDIOHSTSTRMOUT Out;
+    };
+    /** Pointer to driver instance. */
+    PDRVHOSTPULSEAUDIO     pDrv;
+    /** DAC/ADC buffer. */
+    void                  *pvPCMBuf;
+    /** Size (in bytes) of DAC/ADC buffer. */
+    uint32_t               cbPCMBuf;
+    /** Pointer to opaque PulseAudio stream. */
+    pa_stream             *pStream;
+    /** Pulse sample format and attribute specification. */
+    pa_sample_spec         SampleSpec;
+    /** Pulse playback and buffer metrics. */
+    pa_buffer_attr         BufAttr;
+    int                    fOpSuccess;
+    /** Pointer to Pulse sample peeking buffer. */
+    const uint8_t         *pu8PeekBuf;
+    /** Current size (in bytes) of peeking data in
+     *  buffer. */
+    size_t                 cbPeekBuf;
+    /** Our offset (in bytes) in peeking buffer. */
+    size_t                 offPeekBuf;
+    pa_operation          *pDrainOp;
+} PULSEAUDIOSTREAM, *PPULSEAUDIOSTREAM;
+
+/* The desired buffer length in milliseconds. Will be the target total stream
+ * latency on newer version of pulse. Apparent latency can be less (or more.)
+ */
+typedef struct PULSEAUDIOCFG
+{
+    RTMSINTERVAL buffer_msecs_out;
+    RTMSINTERVAL buffer_msecs_in;
+} PULSEAUDIOCFG, *PPULSEAUDIOCFG;
+
+static PULSEAUDIOCFG s_pulseCfg =
+{
+    100, /* buffer_msecs_out */
+    100  /* buffer_msecs_in */
+};
+
+/** Makes DRVHOSTPULSEAUDIO out of PDMIHOSTAUDIO. */
+#define PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface) \
+    ( (PDRVHOSTPULSEAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPULSEAUDIO, IHostAudio)) )
+
+static int  drvHostPulseAudioError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg);
+static void drvHostPulseAudioCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext);
+
+/**
+ * Signal the main loop to abort. Just signalling isn't sufficient as the
+ * mainloop might not have been entered yet.
+ */
+static void drvHostPulseAudioAbortMainLoop(void)
+{
+    g_fAbortMainLoop = true;
+    pa_threaded_mainloop_signal(g_pMainLoop, 0);
+}
+
+static pa_sample_format_t drvHostPulseAudioFmtToPulse(PDMAUDIOFMT fmt)
+{
+    switch (fmt)
+    {
+        case AUD_FMT_U8:
+            return PA_SAMPLE_U8;
+
+        case AUD_FMT_S16:
+            return PA_SAMPLE_S16LE;
+
+#ifdef PA_SAMPLE_S32LE
+        case AUD_FMT_S32:
+            return PA_SAMPLE_S32LE;
+#endif
+        default:
+            break;
+    }
+
+    AssertMsgFailed(("Format %ld not supported\n", fmt));
+    return PA_SAMPLE_U8;
+}
+
+static int drvHostPulseAudioPulseToFmt(pa_sample_format_t pulsefmt,
+                                       PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
+{
+    switch (pulsefmt)
+    {
+        case PA_SAMPLE_U8:
+            *pFmt = AUD_FMT_U8;
+            *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case PA_SAMPLE_S16LE:
+            *pFmt = AUD_FMT_S16;
+            *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+
+        case PA_SAMPLE_S16BE:
+            *pFmt = AUD_FMT_S16;
+            *pEndianness = PDMAUDIOENDIANNESS_BIG;
+            break;
+
+#ifdef PA_SAMPLE_S32LE
+        case PA_SAMPLE_S32LE:
+            *pFmt = AUD_FMT_S32;
+            *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
+            break;
+#endif
+
+#ifdef PA_SAMPLE_S32BE
+        case PA_SAMPLE_S32BE:
+            *pFmt = AUD_FMT_S32;
+            *pEndianness = PDMAUDIOENDIANNESS_BIG;
+            break;
+#endif
+
+        default:
+            AssertMsgFailed(("Format %ld not supported\n", pulsefmt));
+            return VERR_NOT_SUPPORTED;
+    }
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Synchronously wait until an operation completed.
+ */
+static int drvHostPulseAudioWaitFor(pa_operation *pOP, RTMSINTERVAL cMsTimeout)
+{
+    AssertPtrReturn(pOP, VERR_INVALID_POINTER);
+
+    int rc = VINF_SUCCESS;
+    if (pOP)
+    {
+        uint64_t u64StartMs = RTTimeMilliTS();
+        while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING)
+        {
+            if (!g_fAbortMainLoop)
+                pa_threaded_mainloop_wait(g_pMainLoop);
+            g_fAbortMainLoop = false;
+
+            uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
+            if (u64ElapsedMs >= cMsTimeout)
+            {
+                rc = VERR_TIMEOUT;
+                break;
+            }
+        }
+
+        pa_operation_unref(pOP);
+    }
+
+    return rc;
+}
+
+/**
+ * Context status changed.
+ */
+static void drvHostPulseAudioCbCtxState(pa_context *pContext, void *pvUser)
+{
+    AssertPtrReturnVoid(pContext);
+    NOREF(pvUser);
+
+    switch (pa_context_get_state(pContext))
+    {
+        case PA_CONTEXT_READY:
+        case PA_CONTEXT_TERMINATED:
+            drvHostPulseAudioAbortMainLoop();
+            break;
+
+        case PA_CONTEXT_FAILED:
+            LogRel(("PulseAudio: Audio input/output stopped!\n"));
+            drvHostPulseAudioAbortMainLoop();
+            break;
+
+        default:
+            break;
+    }
+}
+
+/**
+ * Callback called when our pa_stream_drain operation was completed.
+ */
+static void drvHostPulseAudioCbStreamDrain(pa_stream *pStream, int fSuccess, void *pvContext)
+{
+    AssertPtrReturnVoid(pStream);
+
+    PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext;
+    AssertPtrReturnVoid(pStrm);
+
+    pStrm->fOpSuccess = fSuccess;
+    if (fSuccess)
+    {
+        pa_operation_unref(pa_stream_cork(pStream, 1,
+                                          drvHostPulseAudioCbSuccess, pvContext));
+    }
+    else
+        drvHostPulseAudioError(pStrm->pDrv, "Failed to drain stream");
+
+    pa_operation_unref(pStrm->pDrainOp);
+    pStrm->pDrainOp = NULL;
+}
+
+/**
+ * Stream status changed.
+ */
+static void drvHostPulseAudioCbStreamState(pa_stream *pStream, void *pvContext)
+{
+    AssertPtrReturnVoid(pStream);
+    NOREF(pvContext);
+
+    switch (pa_stream_get_state(pStream))
+    {
+        case PA_STREAM_READY:
+        case PA_STREAM_FAILED:
+        case PA_STREAM_TERMINATED:
+            drvHostPulseAudioAbortMainLoop();
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void drvHostPulseAudioCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext)
+{
+    AssertPtrReturnVoid(pStream);
+
+    PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext;
+    AssertPtrReturnVoid(pStrm);
+
+    pStrm->fOpSuccess = fSuccess;
+
+    if (fSuccess)
+        drvHostPulseAudioAbortMainLoop();
+    else
+        drvHostPulseAudioError(pStrm->pDrv, "Failed to finish stream operation");
+}
+
+static int drvHostPulseAudioOpen(bool fIn, const char *pszName,
+                                 pa_sample_spec *pSampleSpec, pa_buffer_attr *pBufAttr,
+                                 pa_stream **ppStream)
+{
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSampleSpec, VERR_INVALID_POINTER);
+    AssertPtrReturn(pBufAttr, VERR_INVALID_POINTER);
+    AssertPtrReturn(ppStream, VERR_INVALID_POINTER);
+
+    if (!pa_sample_spec_valid(pSampleSpec))
+    {
+        LogRel(("PulseAudio: Unsupported sample specification for stream \"%s\"\n",
+                pszName));
+        return VERR_NOT_SUPPORTED;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    pa_stream *pStream = NULL;
+    uint32_t   flags = PA_STREAM_NOFLAGS;
+
+    LogFunc(("Opening \"%s\", rate=%dHz, channels=%d, format=%s\n",
+             pszName, pSampleSpec->rate, pSampleSpec->channels,
+             pa_sample_format_to_string(pSampleSpec->format)));
+
+    pa_threaded_mainloop_lock(g_pMainLoop);
+
+    do
+    {
+        if (!(pStream = pa_stream_new(g_pContext, pszName, pSampleSpec,
+                                      NULL /* pa_channel_map */)))
+        {
+            LogRel(("PulseAudio: Could not create stream \"%s\"\n", pszName));
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        pa_stream_set_state_callback(pStream, drvHostPulseAudioCbStreamState, NULL);
+
+#if PA_API_VERSION >= 12
+        /* XXX */
+        flags |= PA_STREAM_ADJUST_LATENCY;
+#endif
+
+#if 0
+        /* Not applicable as we don't use pa_stream_get_latency() and pa_stream_get_time(). */
+        flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
+#endif
+        /* No input/output right away after the stream was started. */
+        flags |= PA_STREAM_START_CORKED;
+
+        if (fIn)
+        {
+            LogFunc(("Input stream attributes: maxlength=%d fragsize=%d\n",
+                     pBufAttr->maxlength, pBufAttr->fragsize));
+
+            if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags) < 0)
+            {
+                LogRel(("PulseAudio: Could not connect input stream \"%s\": %s\n",
+                        pszName, pa_strerror(pa_context_errno(g_pContext))));
+                rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                break;
+            }
+        }
+        else
+        {
+            LogFunc(("Output buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n",
+                     pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
+
+            if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags,
+                                           /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
+            {
+                LogRel(("PulseAudio: Could not connect playback stream \"%s\": %s\n",
+                        pszName, pa_strerror(pa_context_errno(g_pContext))));
+                rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                break;
+            }
+        }
+
+        /* Wait until the stream is ready. */
+        for (;;)
+        {
+            if (!g_fAbortMainLoop)
+                pa_threaded_mainloop_wait(g_pMainLoop);
+            g_fAbortMainLoop = false;
+
+            pa_stream_state_t sstate = pa_stream_get_state(pStream);
+            if (sstate == PA_STREAM_READY)
+                break;
+            else if (   sstate == PA_STREAM_FAILED
+                     || sstate == PA_STREAM_TERMINATED)
+            {
+                LogRel(("PulseAudio: Failed to initialize stream \"%s\" (state %ld)\n",
+                        pszName, sstate));
+                rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                break;
+            }
+        }
+
+        if (RT_FAILURE(rc))
+            break;
+
+        const pa_buffer_attr *pBufAttrObtained = pa_stream_get_buffer_attr(pStream);
+        AssertPtr(pBufAttrObtained);
+        memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr));
+
+        if (fIn)
+            LogFunc(("Obtained record buffer attributes: maxlength=%RU32, fragsize=%RU32\n",
+                     pBufAttr->maxlength, pBufAttr->fragsize));
+        else
+            LogFunc(("Obtained playback buffer attributes: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d\n",
+                     pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
+
+    }
+    while (0);
+
+    if (   RT_FAILURE(rc)
+        && pStream)
+        pa_stream_disconnect(pStream);
+
+    pa_threaded_mainloop_unlock(g_pMainLoop);
+
+    if (RT_FAILURE(rc))
+    {
+        if (pStream)
+            pa_stream_unref(pStream);
+    }
+    else
+        *ppStream = pStream;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    LogFlowFuncEnter();
+
+    int rc = audioLoadPulseLib();
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("PulseAudio: Failed to load the PulseAudio shared library! Error %Rrc\n", rc));
+        return rc;
+    }
+
+    bool fLocked = false;
+
+    do
+    {
+        if (!(g_pMainLoop = pa_threaded_mainloop_new()))
+        {
+            LogRel(("PulseAudio: Failed to allocate main loop: %s\n",
+                     pa_strerror(pa_context_errno(g_pContext))));
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VirtualBox")))
+        {
+            LogRel(("PulseAudio: Failed to allocate context: %s\n",
+                     pa_strerror(pa_context_errno(g_pContext))));
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        if (pa_threaded_mainloop_start(g_pMainLoop) < 0)
+        {
+            LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n",
+                     pa_strerror(pa_context_errno(g_pContext))));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        g_fAbortMainLoop = false;
+        pa_context_set_state_callback(g_pContext, drvHostPulseAudioCbCtxState, NULL);
+        pa_threaded_mainloop_lock(g_pMainLoop);
+        fLocked = true;
+
+        if (pa_context_connect(g_pContext, NULL /* pszServer */,
+                               PA_CONTEXT_NOFLAGS, NULL) < 0)
+        {
+            LogRel(("PulseAudio: Failed to connect to server: %s\n",
+                     pa_strerror(pa_context_errno(g_pContext))));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        /* Wait until the g_pContext is ready */
+        for (;;)
+        {
+            if (!g_fAbortMainLoop)
+                pa_threaded_mainloop_wait(g_pMainLoop);
+            g_fAbortMainLoop = false;
+
+            pa_context_state_t cstate = pa_context_get_state(g_pContext);
+            if (cstate == PA_CONTEXT_READY)
+                break;
+            else if (   cstate == PA_CONTEXT_TERMINATED
+                     || cstate == PA_CONTEXT_FAILED)
+            {
+                LogRel(("PulseAudio: Failed to initialize context (state %d)\n", cstate));
+                rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+                break;
+            }
+        }
+    }
+    while (0);
+
+    if (fLocked)
+        pa_threaded_mainloop_unlock(g_pMainLoop);
+
+    if (RT_FAILURE(rc))
+    {
+        if (g_pMainLoop)
+            pa_threaded_mainloop_stop(g_pMainLoop);
+
+        if (g_pContext)
+        {
+            pa_context_disconnect(g_pContext);
+            pa_context_unref(g_pContext);
+            g_pContext = NULL;
+        }
+
+        if (g_pMainLoop)
+        {
+            pa_threaded_mainloop_free(g_pMainLoop);
+            g_pMainLoop = NULL;
+        }
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioInitOut(PPDMIHOSTAUDIO pInterface,
+                                                  PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                  PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                  uint32_t *pcSamples)
+{
+    RT_NOREF(pCfgAcq);
+    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,     VERR_INVALID_POINTER);
+    /* pcSamples is optional. */
+
+    PDRVHOSTPULSEAUDIO pDrv = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+    PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
+
+    LogFlowFuncEnter();
+
+    pThisStrmOut->pDrainOp            = NULL;
+
+    pThisStrmOut->SampleSpec.format   = drvHostPulseAudioFmtToPulse(pCfgReq->enmFormat);
+    pThisStrmOut->SampleSpec.rate     = pCfgReq->uHz;
+    pThisStrmOut->SampleSpec.channels = pCfgReq->cChannels;
+
+    /* Note that setting maxlength to -1 does not work on PulseAudio servers
+     * older than 0.9.10. So use the suggested value of 3/2 of tlength */
+    pThisStrmOut->BufAttr.tlength     =   (pa_bytes_per_second(&pThisStrmOut->SampleSpec)
+                                        * s_pulseCfg.buffer_msecs_out) / 1000;
+    pThisStrmOut->BufAttr.maxlength   = (pThisStrmOut->BufAttr.tlength * 3) / 2;
+    pThisStrmOut->BufAttr.prebuf      = -1; /* Same as tlength */
+    pThisStrmOut->BufAttr.minreq      = -1; /* Pulse should set something sensible for minreq on it's own */
+
+    /* Note that the struct BufAttr is updated to the obtained values after this call! */
+    char achName[64];
+    RTStrPrintf(achName, sizeof(achName), "%.32s (out)", pDrv->pszStreamName);
+    int rc = drvHostPulseAudioOpen(false /* fIn */, achName, &pThisStrmOut->SampleSpec, &pThisStrmOut->BufAttr,
+                                   &pThisStrmOut->pStream);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    PDMAUDIOSTREAMCFG streamCfg;
+    rc = drvHostPulseAudioPulseToFmt(pThisStrmOut->SampleSpec.format,
+                                     &streamCfg.enmFormat, &streamCfg.enmEndianness);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("PulseAudio: Cannot find audio output format %ld\n", pThisStrmOut->SampleSpec.format));
+        return rc;
+    }
+
+    streamCfg.uHz       = pThisStrmOut->SampleSpec.rate;
+    streamCfg.cChannels = pThisStrmOut->SampleSpec.channels;
+
+    rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cbBuf  = RT_MIN(pThisStrmOut->BufAttr.tlength * 2,
+                                 pThisStrmOut->BufAttr.maxlength); /** @todo Make this configurable! */
+        if (cbBuf)
+        {
+            pThisStrmOut->pvPCMBuf = RTMemAllocZ(cbBuf);
+            if (pThisStrmOut->pvPCMBuf)
+            {
+                pThisStrmOut->cbPCMBuf = cbBuf;
+
+                uint32_t cSamples = cbBuf >> pHstStrmOut->Props.cShift;
+                if (pcSamples)
+                    *pcSamples = cSamples;
+
+                /* Save pointer to driver instance. */
+                pThisStrmOut->pDrv = pDrv;
+
+                LogFunc(("cbBuf=%RU32, cSamples=%RU32\n", cbBuf, cSamples));
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+        else
+            rc = VERR_INVALID_PARAMETER;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(bool) drvHostPulseAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    NOREF(pInterface);
+    NOREF(enmDir);
+    return true; /* Always all enabled. */
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioInitIn(PPDMIHOSTAUDIO pInterface,
+                                                 PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                                 PDMAUDIORECSOURCE enmRecSource,
+                                                 uint32_t *pcSamples)
+{
+    RT_NOREF(pCfgAcq, enmRecSource);
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
+    /* pcSamples is optional. */
+
+    PDRVHOSTPULSEAUDIO pDrv = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+    PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
+
+    LogFunc(("enmRecSrc=%ld\n", enmRecSource));
+
+    pThisStrmIn->SampleSpec.format   = drvHostPulseAudioFmtToPulse(pCfgReq->enmFormat);
+    pThisStrmIn->SampleSpec.rate     = pCfgReq->uHz;
+    pThisStrmIn->SampleSpec.channels = pCfgReq->cChannels;
+
+    /* XXX check these values */
+    pThisStrmIn->BufAttr.fragsize    = (pa_bytes_per_second(&pThisStrmIn->SampleSpec)
+                                   * s_pulseCfg.buffer_msecs_in) / 1000;
+    pThisStrmIn->BufAttr.maxlength   = (pThisStrmIn->BufAttr.fragsize * 3) / 2;
+    /* Note: Other members of pa_buffer_attr are ignored for record streams. */
+
+    char achName[64];
+    RTStrPrintf(achName, sizeof(achName), "%.32s (in)", pDrv->pszStreamName);
+    int rc = drvHostPulseAudioOpen(true /* fIn */, achName, &pThisStrmIn->SampleSpec, &pThisStrmIn->BufAttr,
+                                   &pThisStrmIn->pStream);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    PDMAUDIOSTREAMCFG streamCfg;
+    rc = drvHostPulseAudioPulseToFmt(pThisStrmIn->SampleSpec.format, &streamCfg.enmFormat,
+                                     &streamCfg.enmEndianness);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("PulseAudio: Cannot find audio capture format %ld\n", pThisStrmIn->SampleSpec.format));
+        return rc;
+    }
+
+    streamCfg.uHz       = pThisStrmIn->SampleSpec.rate;
+    streamCfg.cChannels = pThisStrmIn->SampleSpec.channels;
+
+    rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cSamples = RT_MIN(pThisStrmIn->BufAttr.fragsize * 10, pThisStrmIn->BufAttr.maxlength)
+                            >> pHstStrmIn->Props.cShift;
+        LogFunc(("cShift=%RU8, cSamples=%RU32\n", pHstStrmIn->Props.cShift, cSamples));
+
+        if (pcSamples)
+            *pcSamples = cSamples;
+
+        /* Save pointer to driver instance. */
+        pThisStrmIn->pDrv = pDrv;
+
+        pThisStrmIn->pu8PeekBuf = NULL;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                    uint32_t *pcSamplesCaptured)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    /* pcSamplesPlayed is optional. */
+
+    PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
+
+    /* We should only call pa_stream_readable_size() once and trust the first value. */
+    pa_threaded_mainloop_lock(g_pMainLoop);
+    size_t cbAvail = pa_stream_readable_size(pThisStrmIn->pStream);
+    pa_threaded_mainloop_unlock(g_pMainLoop);
+
+    if (cbAvail == (size_t)-1)
+        return drvHostPulseAudioError(pThisStrmIn->pDrv, "Failed to determine input data size");
+
+    /* If the buffer was not dropped last call, add what remains. */
+    if (pThisStrmIn->pu8PeekBuf)
+    {
+        Assert(pThisStrmIn->cbPeekBuf >= pThisStrmIn->offPeekBuf);
+        cbAvail += (pThisStrmIn->cbPeekBuf - pThisStrmIn->offPeekBuf);
+    }
+
+    if (!cbAvail) /* No data? Bail out. */
+    {
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = 0;
+        return VINF_SUCCESS;
+    }
+
+    int rc = VINF_SUCCESS;
+    size_t cbToRead = RT_MIN(cbAvail, AudioMixBufFreeBytes(&pHstStrmIn->MixBuf));
+
+    LogFlowFunc(("cbToRead=%zu, cbAvail=%zu, offPeekBuf=%zu, cbPeekBuf=%zu\n",
+                 cbToRead, cbAvail, pThisStrmIn->offPeekBuf, pThisStrmIn->cbPeekBuf));
+
+    uint32_t cWrittenTotal = 0;
+
+    while (cbToRead)
+    {
+        /* If there is no data, do another peek. */
+        if (!pThisStrmIn->pu8PeekBuf)
+        {
+            pa_threaded_mainloop_lock(g_pMainLoop);
+            pa_stream_peek(pThisStrmIn->pStream,
+                           (const void**)&pThisStrmIn->pu8PeekBuf, &pThisStrmIn->cbPeekBuf);
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+
+            pThisStrmIn->offPeekBuf = 0;
+
+            /* No data anymore?
+             * Note: If there's a data hole (cbPeekBuf then contains the length of the hole)
+             *       we need to drop the stream lateron. */
+            if (   !pThisStrmIn->pu8PeekBuf
+                && !pThisStrmIn->cbPeekBuf)
+            {
+                break;
+            }
+        }
+
+        Assert(pThisStrmIn->cbPeekBuf >= pThisStrmIn->offPeekBuf);
+        size_t cbToWrite = RT_MIN(pThisStrmIn->cbPeekBuf - pThisStrmIn->offPeekBuf, cbToRead);
+
+        LogFlowFunc(("cbToRead=%zu, cbToWrite=%zu, offPeekBuf=%zu, cbPeekBuf=%zu, pu8PeekBuf=%p\n",
+                     cbToRead, cbToWrite,
+                     pThisStrmIn->offPeekBuf, pThisStrmIn->cbPeekBuf, pThisStrmIn->pu8PeekBuf));
+
+        if (cbToWrite)
+        {
+            uint32_t cWritten;
+            rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
+                                      pThisStrmIn->pu8PeekBuf + pThisStrmIn->offPeekBuf,
+                                      cbToWrite, &cWritten);
+            if (RT_FAILURE(rc))
+                break;
+
+            uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
+
+            Assert(cbToRead >= cbWritten);
+            cbToRead -= cbWritten;
+            cWrittenTotal += cWritten;
+            pThisStrmIn->offPeekBuf += cbWritten;
+        }
+
+        if (/* Nothing to write anymore? Drop the buffer. */
+               !cbToWrite
+            /* Was there a hole in the peeking buffer? Drop it. */
+            || !pThisStrmIn->pu8PeekBuf
+            /* If the buffer is done, drop it. */
+            || pThisStrmIn->offPeekBuf == pThisStrmIn->cbPeekBuf)
+        {
+            pa_threaded_mainloop_lock(g_pMainLoop);
+            pa_stream_drop(pThisStrmIn->pStream);
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+
+            pThisStrmIn->pu8PeekBuf = NULL;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cProcessed = 0;
+        if (cWrittenTotal)
+            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
+                                        &cProcessed);
+
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cWrittenTotal;
+
+        LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
+                     cWrittenTotal, cProcessed, rc));
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                  uint32_t *pcSamplesPlayed)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    /* pcSamplesPlayed is optional. */
+
+    PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
+
+    int rc = VINF_SUCCESS;
+    uint32_t cbReadTotal = 0;
+
+    uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+    if (!cLive)
+    {
+        LogFlowFunc(("%p: No live samples, skipping\n", pHstStrmOut));
+
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = 0;
+        return VINF_SUCCESS;
+    }
+
+    pa_threaded_mainloop_lock(g_pMainLoop);
+
+    do
+    {
+        size_t cbWriteable = pa_stream_writable_size(pThisStrmOut->pStream);
+        if (cbWriteable == (size_t)-1)
+        {
+            rc = drvHostPulseAudioError(pThisStrmOut->pDrv, "Failed to determine output data size");
+            break;
+        }
+
+        size_t cbLive   = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cLive);
+        size_t cbToRead = RT_MIN(cbWriteable, cbLive);
+
+        LogFlowFunc(("cbToRead=%zu, cbWriteable=%zu, cbLive=%zu\n",
+                     cbToRead, cbWriteable, cbLive));
+
+        uint32_t cRead, cbRead;
+        while (cbToRead)
+        {
+            rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvPCMBuf,
+                                     RT_MIN(cbToRead, pThisStrmOut->cbPCMBuf), &cRead);
+            if (   !cRead
+                || RT_FAILURE(rc))
+            {
+                break;
+            }
+
+            cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
+            if (pa_stream_write(pThisStrmOut->pStream, pThisStrmOut->pvPCMBuf, cbRead, NULL /* Cleanup callback */,
+                                0, PA_SEEK_RELATIVE) < 0)
+            {
+                rc = drvHostPulseAudioError(pThisStrmOut->pDrv, "Failed to write to output stream");
+                break;
+            }
+
+            Assert(cbToRead >= cbRead);
+            cbToRead    -= cbRead;
+            cbReadTotal += cbRead;
+
+            LogFlowFunc(("\tcRead=%RU32 (%zu bytes) cbReadTotal=%RU32, cbToRead=%RU32\n",
+                         cRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead), cbReadTotal, cbToRead));
+        }
+
+    } while (0);
+
+    pa_threaded_mainloop_unlock(g_pMainLoop);
+
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
+        if (cReadTotal)
+            AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
+
+        if (pcSamplesPlayed)
+            *pcSamplesPlayed = cReadTotal;
+
+        LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n", cReadTotal, cbReadTotal, rc));
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/** @todo Implement va handling. */
+static int drvHostPulseAudioError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(szMsg, VERR_INVALID_POINTER);
+
+    if (pThis->cLogErrors++ < VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS)
+    {
+        int rc2 = pa_context_errno(g_pContext);
+        LogRel(("PulseAudio: %s: %s\n", szMsg, pa_strerror(rc2)));
+    }
+
+    /** @todo Implement some PulseAudio -> IPRT mapping here. */
+    return VERR_GENERAL_FAILURE;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
+    if (pThisStrmIn->pStream)
+    {
+        pa_threaded_mainloop_lock(g_pMainLoop);
+        pa_stream_disconnect(pThisStrmIn->pStream);
+        pa_stream_unref(pThisStrmIn->pStream);
+        pa_threaded_mainloop_unlock(g_pMainLoop);
+
+        pThisStrmIn->pStream = NULL;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
+    if (pThisStrmOut->pStream)
+    {
+        pa_threaded_mainloop_lock(g_pMainLoop);
+        pa_stream_disconnect(pThisStrmOut->pStream);
+        pa_stream_unref(pThisStrmOut->pStream);
+        pa_threaded_mainloop_unlock(g_pMainLoop);
+
+        pThisStrmOut->pStream = NULL;
+    }
+
+    if (pThisStrmOut->pvPCMBuf)
+    {
+        RTMemFree(pThisStrmOut->pvPCMBuf);
+        pThisStrmOut->pvPCMBuf = NULL;
+
+        pThisStrmOut->cbPCMBuf = 0;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioControlOut(PPDMIHOSTAUDIO pInterface,
+                                                     PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+    PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
+    int rc = VINF_SUCCESS;
+
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            pa_threaded_mainloop_lock(g_pMainLoop);
+
+            if (   pThisStrmOut->pDrainOp
+                && pa_operation_get_state(pThisStrmOut->pDrainOp) != PA_OPERATION_DONE)
+            {
+                pa_operation_cancel(pThisStrmOut->pDrainOp);
+                pa_operation_unref(pThisStrmOut->pDrainOp);
+
+                pThisStrmOut->pDrainOp = NULL;
+            }
+            else
+            {
+                /* This should return immediately. */
+                rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmOut->pStream, 0,
+                                                             drvHostPulseAudioCbSuccess, pThisStrmOut),
+                                              15 * 1000 /* 15s timeout */);
+            }
+
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            /* Pause audio output (the Pause bit of the AC97 x_CR register is set).
+             * Note that we must return immediately from here! */
+            pa_threaded_mainloop_lock(g_pMainLoop);
+            if (!pThisStrmOut->pDrainOp)
+            {
+                /* This should return immediately. */
+                rc = drvHostPulseAudioWaitFor(pa_stream_trigger(pThisStrmOut->pStream,
+                                                                drvHostPulseAudioCbSuccess, pThisStrmOut),
+                                              15 * 1000 /* 15s timeout */);
+                if (RT_LIKELY(RT_SUCCESS(rc)))
+                    pThisStrmOut->pDrainOp = pa_stream_drain(pThisStrmOut->pStream,
+                                                             drvHostPulseAudioCbStreamDrain, pThisStrmOut);
+            }
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                                    PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
+    int rc = VINF_SUCCESS;
+
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            pa_threaded_mainloop_lock(g_pMainLoop);
+            /* This should return immediately. */
+            rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmIn->pStream, 0 /* Play / resume */,
+                                                         drvHostPulseAudioCbSuccess, pThisStrmIn),
+                                          15 * 1000 /* 15s timeout */);
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            pa_threaded_mainloop_lock(g_pMainLoop);
+            if (pThisStrmIn->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
+            {
+                pa_stream_drop(pThisStrmIn->pStream);
+                pThisStrmIn->pu8PeekBuf = NULL;
+            }
+            /* This should return immediately. */
+            rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmIn->pStream, 1 /* Stop / pause */,
+                                                         drvHostPulseAudioCbSuccess, pThisStrmIn),
+                                          15 * 1000 /* 15s timeout */);
+            pa_threaded_mainloop_unlock(g_pMainLoop);
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
+            rc = VERR_INVALID_PARAMETER;
+            break;
+    }
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    NOREF(pInterface);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    pCfg->cbStreamOut     = sizeof(PULSEAUDIOSTREAM);
+    pCfg->cbStreamIn      = sizeof(PULSEAUDIOSTREAM);
+    pCfg->cMaxHstStrmsOut = UINT32_MAX;
+    pCfg->cMaxHstStrmsIn  = UINT32_MAX;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) drvHostPulseAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+
+    LogFlowFuncEnter();
+
+    if (g_pMainLoop)
+        pa_threaded_mainloop_stop(g_pMainLoop);
+
+    if (g_pContext)
+    {
+        pa_context_disconnect(g_pContext);
+        pa_context_unref(g_pContext);
+        g_pContext = NULL;
+    }
+
+    if (g_pMainLoop)
+    {
+        pa_threaded_mainloop_free(g_pMainLoop);
+        g_pMainLoop = NULL;
+    }
+
+    LogFlowFuncLeave();
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvHostPulseAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    AssertPtrReturn(pInterface, NULL);
+    AssertPtrReturn(pszIID, NULL);
+
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+
+    return NULL;
+}
+
+/**
+ * Constructs a PulseAudio Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostPulseAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(fFlags);
+    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
+
+    PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
+    LogRel(("Audio: Initializing PulseAudio driver\n"));
+
+    CFGMR3QueryStringAlloc(pCfg, "StreamName", &pThis->pszStreamName);
+
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvHostPulseAudioQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostPulseAudio);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Destructs a PulseAudio Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(void) drvHostPulseAudioDestruct(PPDMDRVINS pDrvIns)
+{
+    PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
+    LogFlowFuncEnter();
+    if (pThis->pszStreamName)
+    {
+        MMR3HeapFree(pThis->pszStreamName);
+        pThis->pszStreamName = NULL;
+    }
+}
+
+/**
+ * Char driver registration record.
+ */
+const PDMDRVREG g_DrvHostPulseAudio =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "PulseAudio",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Pulse Audio host driver",
+    /* fFlags */
+     PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVHOSTPULSEAUDIO),
+    /* pfnConstruct */
+    drvHostPulseAudioConstruct,
+    /* pfnDestruct */
+    drvHostPulseAudioDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
+#if 0 // unused
+static struct audio_option pulse_options[] =
+{
+    {"DAC_MS", AUD_OPT_INT, &s_pulseCfg.buffer_msecs_out,
+     "DAC period size in milliseconds", NULL, 0},
+    {"ADC_MS", AUD_OPT_INT, &s_pulseCfg.buffer_msecs_in,
+     "ADC period size in milliseconds", NULL, 0},
+
+    NULL
+};
+#endif
diff --git a/src/VBox/Devices/Audio/DevIchHdaCodec.cpp b/src/VBox/Devices/Audio_50/HDACodec.cpp
similarity index 61%
rename from src/VBox/Devices/Audio/DevIchHdaCodec.cpp
rename to src/VBox/Devices/Audio_50/HDACodec.cpp
index 4231f5c..cc42d62 100644
--- a/src/VBox/Devices/Audio/DevIchHdaCodec.cpp
+++ b/src/VBox/Devices/Audio_50/HDACodec.cpp
@@ -1,4 +1,4 @@
-/* $Id: DevIchHdaCodec.cpp $ */
+/* $Id: HDACodec.cpp $ */
 /** @file
  * DevIchHdaCodec - VBox ICH Intel HD Audio Codec.
  *
@@ -34,10 +34,7 @@
 #include <iprt/cpp/utils.h>
 
 #include "VBoxDD.h"
-#include "DrvAudio.h"
 #include "DevIchHdaCodec.h"
-#include "DevIchHdaCommon.h"
-#include "AudioMixer.h"
 
 
 /*********************************************************************************************************************************
@@ -105,17 +102,9 @@
 #define CODEC_MAKE_F00_00(vendorID, deviceID)              (((vendorID) << 16) | (deviceID))
 #define CODEC_F00_00_VENDORID(f00_00)                      (((f00_00) >> 16) & 0xFFFF)
 #define CODEC_F00_00_DEVICEID(f00_00)                      ((f00_00) & 0xFFFF)
-
-/** RevisionID (7.3.4.2). */
-#define CODEC_MAKE_F00_02(majRev, minRev, venFix, venProg, stepFix, stepProg) \
-    (  (((majRev)   & 0xF) << 20) \
-     | (((minRev)   & 0xF) << 16) \
-     | (((venFix)   & 0xF) << 12) \
-     | (((venProg)  & 0xF) << 8)  \
-     | (((stepFix)  & 0xF) << 4)  \
-     |  ((stepProg) & 0xF))
-
-/** Subordinate node count (7.3.4.3). */
+/* RevisionID (7.3.4.2)*/
+#define CODEC_MAKE_F00_02(MajRev, MinRev, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID))
+/* Subordinate node count (7.3.4.3)*/
 #define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF))
 #define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04)          (((f00_04) >> 16) & 0xFF)
 #define CODEC_F00_04_TO_NODE_COUNT(f00_04)                 ((f00_04) & 0xFF)
@@ -130,19 +119,15 @@
 #define CODEC_F00_05_MFG                                   (0x2)
 #define CODEC_F00_05_IS_UNSOL(f00_05)                      RT_BOOL((f00_05) & RT_BIT(8))
 #define CODEC_F00_05_GROUP(f00_05)                         ((f00_05) & 0xff)
-/* Audio Function Group capabilities (7.3.4.5). */
+/*  Audio Function Group capabilities (7.3.4.5) */
 #define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF))
 #define CODEC_F00_08_BEEP_GEN(f00_08)                      ((f00_08) & RT_BIT(16)
 
-/* Converter Stream, Channel (7.3.3.11). */
-#define CODEC_F00_06_GET_STREAM_ID(cmd)                    (((cmd) >> 4) & 0x0F)
-#define CODEC_F00_06_GET_CHANNEL_ID(cmd)                   (((cmd) & 0x0F))
-
-/* Widget Capabilities (7.3.4.6). */
-#define CODEC_MAKE_F00_09(type, delay, chan_ext) \
-    ( (((type)     & 0xF) << 20)            \
-    | (((delay)    & 0xF) << 16)           \
-    | (((chan_ext) & 0xF) << 13))
+/* Widget Capabilities (7.3.4.6) */
+#define CODEC_MAKE_F00_09(type, delay, chanel_count) \
+    ( (((type) & 0xF) << 20)            \
+    | (((delay) & 0xF) << 16)           \
+    | (((chanel_count) & 0xF) << 13))
 /* note: types 0x8-0xe are reserved */
 #define CODEC_F00_09_TYPE_AUDIO_OUTPUT                     (0x0)
 #define CODEC_F00_09_TYPE_AUDIO_INPUT                      (0x1)
@@ -166,7 +151,7 @@
 #define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE                  RT_BIT(3)
 #define CODEC_F00_09_CAP_OUT_AMP_PRESENT                   RT_BIT(2)
 #define CODEC_F00_09_CAP_IN_AMP_PRESENT                    RT_BIT(1)
-#define CODEC_F00_09_CAP_STEREO                            RT_BIT(0)
+#define CODEC_F00_09_CAP_LSB                               RT_BIT(0)
 
 #define CODEC_F00_09_TYPE(f00_09)                          (((f00_09) >> 20) & 0xF)
 
@@ -222,8 +207,8 @@
 #define CODEC_F00_0C_CAP_BALANCED_IO                       RT_BIT(6)
 #define CODEC_F00_0C_CAP_INPUT                             RT_BIT(5)
 #define CODEC_F00_0C_CAP_OUTPUT                            RT_BIT(4)
-#define CODEC_F00_0C_CAP_HEADPHONE_AMP                     RT_BIT(3)
-#define CODEC_F00_0C_CAP_PRESENCE_DETECT                   RT_BIT(2)
+#define CODEC_F00_0C_CAP_HP                                RT_BIT(3)
+#define CODEC_F00_0C_CAP_PRESENSE_DETECT                   RT_BIT(2)
 #define CODEC_F00_0C_CAP_TRIGGER_REQUIRED                  RT_BIT(1)
 #define CODEC_F00_0C_CAP_IMPENDANCE_SENSE                  RT_BIT(0)
 
@@ -235,16 +220,16 @@
 #define CODEC_F00_0C_IS_CAP_INPUT(f00_0c)                  ((f00_0c) & RT_BIT(5))
 #define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c)                 ((f00_0c) & RT_BIT(4))
 #define CODEC_F00_0C_IS_CAP_HP(f00_0c)                     ((f00_0c) & RT_BIT(3))
-#define CODEC_F00_0C_IS_CAP_PRESENCE_DETECT(f00_0c)        ((f00_0c) & RT_BIT(2))
+#define CODEC_F00_0C_IS_CAP_PRESENSE_DETECT(f00_0c)        ((f00_0c) & RT_BIT(2))
 #define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c)       ((f00_0c) & RT_BIT(1))
 #define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c)       ((f00_0c) & RT_BIT(0))
 
-/* Input Amplifier capabilities (7.3.4.10). */
+/* Input Amplifier capabilities (7.3.4.10) */
 #define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \
-        (  (((mute_cap)  & UINT32_C(0x1))  << 31) \
+        (  (((mute_cap)  & UINT32_C(0x01)) << 31) \
          | (((step_size) & UINT32_C(0xFF)) << 16) \
-         | (((num_steps) & UINT32_C(0xFF)) << 8) \
-         |  ((offset)    & UINT32_C(0xFF)))
+         | (((num_steps) & UINT32_C(0xFF)) <<  8) \
+         | ( (offset)    & UINT32_C(0xFF)) )
 
 #define CODEC_F00_0D_CAP_MUTE                              RT_BIT(7)
 
@@ -253,24 +238,6 @@
 #define CODEC_F00_0D_NUM_STEPS(f00_0d)                     ((((f00_0d) & (0x7F << 8)) >> 8) + 1)
 #define CODEC_F00_0D_OFFSET(f00_0d)                        (  (f00_0d) & 0x7F)
 
-/** Indicates that the amplifier can be muted. */
-#define CODEC_AMP_CAP_MUTE                                 0x1
-/** The amplifier's maximum number of steps. We want
- *  a ~90dB dynamic range, so 64 steps with 1.25dB each
- *  should do the trick.
- *
- *  As we want to map our range to [0..128] values we can avoid
- *  multiplication and simply doing a shift later.
- *
- *  Produces -96dB to +0dB.
- *  "0" indicates a step of 0.25dB, "127" indicates a step of 32dB.
- */
-#define CODEC_AMP_NUM_STEPS                                0x7F
-/** The initial gain offset (and when doing a node reset). */
-#define CODEC_AMP_OFF_INITIAL                              0x7F
-/** The amplifier's gain step size. */
-#define CODEC_AMP_STEP_SIZE                                0x2
-
 /* Output Amplifier capabilities (7.3.4.10) */
 #define CODEC_MAKE_F00_12                                  CODEC_MAKE_F00_0D
 
@@ -279,7 +246,7 @@
 #define CODEC_F00_12_NUM_STEPS(f00_12)                     CODEC_F00_0D_NUM_STEPS(f00_12)
 #define CODEC_F00_12_OFFSET(f00_12)                        CODEC_F00_0D_OFFSET(f00_12)
 
-/* Connection list lenght (7.3.4.11). */
+/* Connection list lenght (7.3.4.11) */
 #define CODEC_MAKE_F00_0E(long_form, length)    \
     (  (((long_form) & 0x1) << 7)               \
      | ((length) & 0x7F))
@@ -304,25 +271,25 @@
 #define CODEC_F00_10_NUM(f00_10)                           (((f00_10) & (0xFF << 8)) >> 8)
 #define CODEC_F00_10_BENING(f00_10)                        ((f00_10) & 0x1)
 
-/* GPIO count (7.3.4.14). */
+/* CP/IO Count (7.3.4.14) */
 #define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \
-    (  (((wake)   & UINT32_C(0x1))  << 31) \
-     | (((unsol)  & UINT32_C(0x1))  << 30) \
+    (  (((wake)   & UINT32_C(0x01)) << 31) \
+     | (((unsol)  & UINT32_C(0x01)) << 30) \
      | (((numgpi) & UINT32_C(0xFF)) << 16) \
-     | (((numgpo) & UINT32_C(0xFF)) << 8) \
-     | ((numgpio) & UINT32_C(0xFF)))
+     | (((numgpo) & UINT32_C(0xFF)) <<  8) \
+     | ((numgpio) & UINT32_C(0xFF)) )
 
-/* Processing States (7.3.3.4). */
+/* Processing States (7.3.3.4) */
 #define CODEC_F03_OFF                                      (0)
 #define CODEC_F03_ON                                       RT_BIT(0)
 #define CODEC_F03_BENING                                   RT_BIT(1)
-/* Power States (7.3.3.10). */
-#define CODEC_MAKE_F05(reset, stopok, error, act, set) \
-    (  (((reset)  & 0x1) << 10) \
-     | (((stopok) & 0x1) << 9) \
-     | (((error)  & 0x1) << 8) \
-     | (((act)    & 0xF) << 4) \
-     | ((set)     & 0xF))
+/* Power States (7.3.3.10) */
+#define CODEC_MAKE_F05(reset, stopok, error, act, set)          \
+    (   (((reset) & 0x1) << 10)                                 \
+      | (((stopok) & 0x1) << 9)                                 \
+      | (((error) & 0x1) << 8)                                  \
+      | (((act) & 0x7) << 4)                                    \
+      | ((set) & 0x7))
 #define CODEC_F05_D3COLD                                   (4)
 #define CODEC_F05_D3                                       (3)
 #define CODEC_F05_D2                                       (2)
@@ -332,20 +299,13 @@
 #define CODEC_F05_IS_RESET(value)                          (((value) & RT_BIT(10)) != 0)
 #define CODEC_F05_IS_STOPOK(value)                         (((value) & RT_BIT(9)) != 0)
 #define CODEC_F05_IS_ERROR(value)                          (((value) & RT_BIT(8)) != 0)
-#define CODEC_F05_ACT(value)                               (((value) & 0xF0) >> 4)
-#define CODEC_F05_SET(value)                               (((value) & 0xF))
+#define CODEC_F05_ACT(value)                               (((value) & 0x7) >> 4)
+#define CODEC_F05_SET(value)                               (((value) & 0x7))
 
 #define CODEC_F05_GE(p0, p1)                               ((p0) <= (p1))
 #define CODEC_F05_LE(p0, p1)                               ((p0) >= (p1))
 
-/* Converter Stream, Channel (7.3.3.11). */
-#define CODEC_MAKE_F06(stream, channel) \
-    (  (((stream)  & 0xF) << 4)         \
-     |  ((channel) & 0xF))
-#define CODEC_F06_STREAM(value)                            ((value) & 0xF0)
-#define CODEC_F06_CHANNEL(value)                           ((value) & 0xF)
-
-/* Pin Widged Control (7.3.3.13). */
+/* Pin Widged Control (7.3.3.13) */
 #define CODEC_F07_VREF_HIZ                                 (0)
 #define CODEC_F07_VREF_50                                  (0x1)
 #define CODEC_F07_VREF_GROUND                              (0x2)
@@ -355,33 +315,57 @@
 #define CODEC_F07_OUT_ENABLE                               RT_BIT(6)
 #define CODEC_F07_OUT_H_ENABLE                             RT_BIT(7)
 
-/* Volume Knob Control (7.3.3.29). */
-#define CODEC_F0F_IS_DIRECT                                RT_BIT(7)
-#define CODEC_F0F_VOLUME                                   (0x7F)
-
-/* Unsolicited enabled (7.3.3.14). */
+/* Unsolicited enabled (7.3.3.14) */
 #define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F))
 
-/* Converter formats (7.3.3.8) and (3.7.1). */
-/* This is the same format as SDnFMT. */
-#define CODEC_MAKE_A                                       HDA_SDFMT_MAKE
-
-#define CODEC_A_TYPE                                       HDA_SDFMT_TYPE
-#define CODEC_A_TYPE_PCM                                   HDA_SDFMT_TYPE_PCM
-#define CODEC_A_TYPE_NON_PCM                               HDA_SDFMT_TYPE_NON_PCM
-
-#define CODEC_A_BASE                                       HDA_SDFMT_BASE
-#define CODEC_A_BASE_48KHZ                                 HDA_SDFMT_BASE_48KHZ
-#define CODEC_A_BASE_44KHZ                                 HDA_SDFMT_BASE_44KHZ
-
-/* Pin Sense (7.3.3.15). */
-#define CODEC_MAKE_F09_ANALOG(fPresent, impedance)  \
-(  (((fPresent) & 0x1) << 31)                       \
- | (((impedance) & UINT32_C(0x7FFFFFFF))))
-#define CODEC_F09_ANALOG_NA    UINT32_C(0x7FFFFFFF)
+/* Converter formats (7.3.3.8) and (3.7.1) */
+#define CODEC_MAKE_A(fNonPCM, f44_1BaseRate, mult, div, bits, chan) \
+    (  (((fNonPCM) & 0x1) << 15)                                    \
+     | (((f44_1BaseRate) & 0x1) << 14)                              \
+     | (((mult) & 0x7) << 11)                                       \
+     | (((div) & 0x7) << 8)                                         \
+     | (((bits) & 0x7) << 4)                                        \
+     | ((chan) & 0xF))
+
+#define CODEC_A_TYPE                                       RT_BIT(15)
+#define CODEC_A_TYPE_PCM                                   (0)
+#define CODEC_A_TYPE_NON_PCM                               (1)
+
+#define CODEC_A_BASE                                       RT_BIT(14)
+#define CODEC_A_BASE_48KHZ                                 (0)
+#define CODEC_A_BASE_44KHZ                                 (1)
+
+#define CODEC_A_MULT_1X                                    (0)
+#define CODEC_A_MULT_2X                                    (1)
+#define CODEC_A_MULT_3X                                    (2)
+#define CODEC_A_MULT_4X                                    (3)
+
+#define CODEC_A_DIV_1X                                     (0)
+#define CODEC_A_DIV_2X                                     (1)
+#define CODEC_A_DIV_3X                                     (2)
+#define CODEC_A_DIV_4X                                     (3)
+#define CODEC_A_DIV_5X                                     (4)
+#define CODEC_A_DIV_6X                                     (5)
+#define CODEC_A_DIV_7X                                     (6)
+#define CODEC_A_DIV_8X                                     (7)
+
+#define CODEC_A_8_BIT                                      (0)
+#define CODEC_A_16_BIT                                     (1)
+#define CODEC_A_20_BIT                                     (2)
+#define CODEC_A_24_BIT                                     (3)
+#define CODEC_A_32_BIT                                     (4)
+
+#define CODEC_A_CHAN_MONO                                  (0)
+#define CODEC_A_CHAN_STEREO                                (1)
+
+/* Pin Sense (7.3.3.15) */
+#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \
+    (  (((fPresent)  & UINT32_C(0x00000001)) << 31) \
+     |  ((impedance) & UINT32_C(0x7FFFFFFF)) )
+#define CODEC_F09_ANALOG_NA    0x7FFFFFFF
 #define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \
-(   (((fPresent)  & UINT32_C(0x1)) << 31)                      \
-  | (((fELDValid) & UINT32_C(0x1)) << 30))
+    (   (((fPresent)  & UINT32_C(0x1)) << 31) \
+      | (((fELDValid) & UINT32_C(0x1)) << 30))
 
 #define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1))
 #define CODEC_FOC_IS_LRSWAP(f0c)                           RT_BOOL((f0c) & RT_BIT(2))
@@ -492,17 +476,16 @@
 /* Configuration's misc */
 #define CODEC_F1C_MISC_MASK                                (0xF)
 #define CODEC_F1C_MISC_SHIFT                               (8)
-#define CODEC_F1C_MISC_NONE                                0
-#define CODEC_F1C_MISC_JACK_NO_PRESENCE_DETECT             RT_BIT(0)
-#define CODEC_F1C_MISC_RESERVED_0                          RT_BIT(1)
-#define CODEC_F1C_MISC_RESERVED_1                          RT_BIT(2)
-#define CODEC_F1C_MISC_RESERVED_2                          RT_BIT(3)
+#define CODEC_F1C_MISC_JACK_DETECT                         (0)
+#define CODEC_F1C_MISC_RESERVED_0                          (1)
+#define CODEC_F1C_MISC_RESERVED_1                          (2)
+#define CODEC_F1C_MISC_RESERVED_2                          (3)
 
 /* Configuration default: Association */
 #define CODEC_F1C_ASSOCIATION_MASK                         (0xF)
 #define CODEC_F1C_ASSOCIATION_SHIFT                        (4)
 
-/** Reserved; don't use. */
+/* Reserved; don't use. */
 #define CODEC_F1C_ASSOCIATION_INVALID                      0x0
 #define CODEC_F1C_ASSOCIATION_GROUP_0                      0x1
 #define CODEC_F1C_ASSOCIATION_GROUP_1                      0x2
@@ -514,27 +497,27 @@
 #define CODEC_F1C_ASSOCIATION_GROUP_7                      0x8
 #define CODEC_F1C_ASSOCIATION_GROUP_15                     0xF
 
-/* Configuration default: Association Sequence. */
+/* Configuration default: Association Sequence */
 #define CODEC_F1C_SEQ_MASK                                 (0xF)
 #define CODEC_F1C_SEQ_SHIFT                                (0)
 
-/* Implementation identification (7.3.3.30). */
+/* Implementation identification (7.3.3.30) */
 #define CODEC_MAKE_F20(bmid, bsku, aid)     \
     (  (((bmid) & 0xFFFF) << 16)            \
      | (((bsku) & 0xFF) << 8)               \
      | (((aid) & 0xFF))                     \
     )
 
-/* Macro definition helping in filling the configuration registers. */
+/* macro definition helping in filling the configuration registers. */
 #define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence)    \
-    (  (((port_connectivity) & 0xF) << CODEC_F1C_PORT_SHIFT)            \
-     | (((location)          & 0xF) << CODEC_F1C_LOCATION_SHIFT)        \
-     | (((device)            & 0xF) << CODEC_F1C_DEVICE_SHIFT)          \
-     | (((connection_type)   & 0xF) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
-     | (((color)             & 0xF) << CODEC_F1C_COLOR_SHIFT)           \
-     | (((misc)              & 0xF) << CODEC_F1C_MISC_SHIFT)            \
-     | (((association)       & 0xF) << CODEC_F1C_ASSOCIATION_SHIFT)     \
-     | (((sequence)          & 0xF)))
+    (  ((port_connectivity) << CODEC_F1C_PORT_SHIFT)          \
+     | ((location) << CODEC_F1C_LOCATION_SHIFT)               \
+     | ((device) << CODEC_F1C_DEVICE_SHIFT)                   \
+     | ((connection_type) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
+     | ((color) << CODEC_F1C_COLOR_SHIFT)                     \
+     | ((misc) << CODEC_F1C_MISC_SHIFT)                       \
+     | ((association) << CODEC_F1C_ASSOCIATION_SHIFT)         \
+     | ((sequence)))
 
 
 /*********************************************************************************************************************************
@@ -550,16 +533,10 @@
  */
 typedef struct CODECCOMMONNODE
 {
-    /** The node's ID. */
-    uint8_t         uID;
-    /** The node's name. */
+    /** Node id - 7 bit format */
+    uint8_t         id;
+    /** The node name. */
     char const     *pszName;
-    /** The SDn ID this node is assigned to.
-     *  0 means not assigned, 1 is SDn0. */
-    uint8_t         uSD;
-    /** The SDn's channel to use.
-     *  Only valid if a valid SDn ID is set. */
-    uint8_t         uChannel;
     /* PRM 5.3.6 */
     uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH];
     uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH];
@@ -607,13 +584,13 @@ AssertNodeSize(DACNODE, 6 + 60);
 typedef struct ADCNODE
 {
     CODECCOMMONNODE node;
-    uint32_t    u32F01_param;
     uint32_t    u32F03_param;
     uint32_t    u32F05_param;
     uint32_t    u32F06_param;
     uint32_t    u32F09_param;
 
     uint32_t    u32A_param;
+    uint32_t    u32F01_param;
     AMPLIFIER   B_params;
 } ADCNODE, *PADCNODE;
 AssertNodeSize(DACNODE, 6 + 60);
@@ -649,18 +626,18 @@ typedef struct AFGCODECNODE
     CODECCOMMONNODE node;
     uint32_t  u32F05_param;
     uint32_t  u32F08_param;
-    uint32_t  u32F17_param;
     uint32_t  u32F20_param;
+    uint32_t  u32F17_param;
 } AFGCODECNODE, *PAFGCODECNODE;
 AssertNodeSize(AFGCODECNODE, 4);
 
 typedef struct PORTNODE
 {
     CODECCOMMONNODE node;
-    uint32_t u32F01_param;
     uint32_t u32F07_param;
     uint32_t u32F08_param;
     uint32_t u32F09_param;
+    uint32_t u32F01_param;
     uint32_t u32F1c_param;
     AMPLIFIER   B_params;
 } PORTNODE, *PPORTNODE;
@@ -670,13 +647,12 @@ typedef struct DIGOUTNODE
 {
     CODECCOMMONNODE node;
     uint32_t u32F01_param;
-    uint32_t u32F05_param;
-    uint32_t u32F07_param;
     uint32_t u32F08_param;
+    uint32_t u32F07_param;
     uint32_t u32F09_param;
     uint32_t u32F1c_param;
 } DIGOUTNODE, *PDIGOUTNODE;
-AssertNodeSize(DIGOUTNODE, 6);
+AssertNodeSize(DIGOUTNODE, 5);
 
 typedef struct DIGINNODE
 {
@@ -746,10 +722,8 @@ typedef struct RESNODE
     uint32_t    u32F06_param;
     uint32_t    u32F07_param;
     uint32_t    u32F1c_param;
-
-    uint32_t    u32A_param;
 } RESNODE, *PRESNODE;
-AssertNodeSize(RESNODE, 5);
+AssertNodeSize(RESNODE, 4);
 
 /**
  * Used for the saved state.
@@ -798,17 +772,13 @@ AssertNodeSize(CODECNODE, 60 + 6);
 #define STAC9220_NID_ADC1                                  0x7  /* In */
 #define STAC9220_NID_SPDIF_OUT                             0x8  /* Out */
 #define STAC9220_NID_SPDIF_IN                              0x9  /* In */
-/** Also known as PIN_A. */
 #define STAC9220_NID_PIN_HEADPHONE0                        0xA  /* In, Out */
 #define STAC9220_NID_PIN_B                                 0xB  /* In, Out */
 #define STAC9220_NID_PIN_C                                 0xC  /* In, Out */
-/** Also known as PIN D. */
 #define STAC9220_NID_PIN_HEADPHONE1                        0xD  /* In, Out */
 #define STAC9220_NID_PIN_E                                 0xE  /* In */
 #define STAC9220_NID_PIN_F                                 0xF  /* In, Out */
-/** Also known as DIGOUT0. */
 #define STAC9220_NID_PIN_SPDIF_OUT                         0x10 /* Out */
-/** Also known as DIGIN. */
 #define STAC9220_NID_PIN_SPDIF_IN                          0x11 /* In */
 #define STAC9220_NID_ADC0_MUX                              0x12 /* In */
 #define STAC9220_NID_ADC1_MUX                              0x13 /* In */
@@ -817,35 +787,48 @@ AssertNodeSize(CODECNODE, 60 + 6);
 #define STAC9220_NID_VOL_KNOB                              0x16
 #define STAC9220_NID_AMP_ADC0                              0x17 /* In */
 #define STAC9220_NID_AMP_ADC1                              0x18 /* In */
-/* Only for STAC9221. */
+/* STAC9221. */
 #define STAC9221_NID_ADAT_OUT                              0x19 /* Out */
 #define STAC9221_NID_I2S_OUT                               0x1A /* Out */
 #define STAC9221_NID_PIN_I2S_OUT                           0x1B /* Out */
 
-/** Number of total nodes emulated. */
-#define STAC9221_NUM_NODES                                 0x1C
-
-/* STAC9220 - Referenced through STAC9220WIDGET in the constructor below. */
-static uint8_t const g_abStac9220Ports[]      = { STAC9220_NID_PIN_HEADPHONE0, STAC9220_NID_PIN_B, STAC9220_NID_PIN_C, STAC9220_NID_PIN_HEADPHONE1, STAC9220_NID_PIN_E, STAC9220_NID_PIN_F, 0 };
-static uint8_t const g_abStac9220Dacs[]       = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0 };
-static uint8_t const g_abStac9220Adcs[]       = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0 };
+#if 1
+/* STAC9220 - Referenced thru STAC9220WIDGET in the constructor below. */
+static uint8_t const g_abStac9220Ports[]      = { 0x0A, 0xB, 0xC, 0xD, 0xE, 0xF, 0};
+static uint8_t const g_abStac9220Dacs[]       = { 0x02, 0x3, 0x4, 0x5, 0};
+static uint8_t const g_abStac9220Adcs[]       = { 0x06, 0x7, 0};
+static uint8_t const g_abStac9220SpdifOuts[]  = { 0x08, 0 };
+static uint8_t const g_abStac9220SpdifIns[]   = { 0x09, 0 };
+static uint8_t const g_abStac9220DigOutPins[] = { 0x10, 0 };
+static uint8_t const g_abStac9220DigInPins[]  = { 0x11, 0 };
+static uint8_t const g_abStac9220AdcVols[]    = { 0x17, 0x18, 0};
+static uint8_t const g_abStac9220AdcMuxs[]    = { 0x12, 0x13, 0};
+static uint8_t const g_abStac9220Pcbeeps[]    = { 0x14, 0 };
+static uint8_t const g_abStac9220Cds[]        = { 0x15, 0 };
+static uint8_t const g_abStac9220VolKnobs[]   = { 0x16, 0 };
+static uint8_t const g_abStac9220Reserveds[]  = { 0x09, 0x19, 0x1a, 0x1b, 0 };
+#else /** @todo Enable this after 5.0 -- needs more testing first. */
+static uint8_t const g_abStac9220Ports[]      = { STAC9220_NID_PIN_HEADPHONE0, STAC9220_NID_PIN_B, STAC9220_NID_PIN_C, STAC9220_NID_PIN_HEADPHONE1, STAC9220_NID_PIN_E, STAC9220_NID_PIN_F, 0};
+static uint8_t const g_abStac9220Dacs[]       = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0};
+static uint8_t const g_abStac9220Adcs[]       = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0};
 static uint8_t const g_abStac9220SpdifOuts[]  = { STAC9220_NID_SPDIF_OUT, 0 };
 static uint8_t const g_abStac9220SpdifIns[]   = { STAC9220_NID_SPDIF_IN, 0 };
 static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
 static uint8_t const g_abStac9220DigInPins[]  = { STAC9220_NID_PIN_SPDIF_IN, 0 };
-static uint8_t const g_abStac9220AdcVols[]    = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0 };
-static uint8_t const g_abStac9220AdcMuxs[]    = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0 };
+static uint8_t const g_abStac9220AdcVols[]    = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0};
+static uint8_t const g_abStac9220AdcMuxs[]    = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0};
 static uint8_t const g_abStac9220Pcbeeps[]    = { STAC9220_NID_PCBEEP, 0 };
 static uint8_t const g_abStac9220Cds[]        = { STAC9220_NID_PIN_CD, 0 };
 static uint8_t const g_abStac9220VolKnobs[]   = { STAC9220_NID_VOL_KNOB, 0 };
 /* STAC 9221. */
 /** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
 static uint8_t const g_abStac9220Reserveds[]  = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
+#endif
 
 /** SSM description of a CODECNODE. */
 static SSMFIELD const g_aCodecNodeFields[] =
 {
-    SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.uID),
+    SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.id),
     SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
     SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.au32F00_param),
     SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.au32F02_param),
@@ -856,7 +839,7 @@ static SSMFIELD const g_aCodecNodeFields[] =
 /** Backward compatibility with v1 of the CODECNODE. */
 static SSMFIELD const g_aCodecNodeFieldsV1[] =
 {
-    SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.uID),
+    SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.id),
     SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
     SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
     SSMFIELD_ENTRY(     CODECSAVEDSTATENODE, Core.au32F00_param),
@@ -867,11 +850,11 @@ static SSMFIELD const g_aCodecNodeFieldsV1[] =
 
 
 
-#if 0 /* unused */
+
 static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     RT_NOREF(pszArgs);
-    for (uint8_t i = 1; i < pThis->cTotalNodes; i++)
+    for (int i = 1; i < 12; i++)
     {
         PCODECNODE pNode = &pThis->paNodes[i];
         AMPLIFIER *pAmp = &pNode->dac.B_params;
@@ -882,595 +865,365 @@ static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp,
         pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
     }
 }
-#endif
-
-static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t uNID, PCODECNODE pNode)
-{
-    LogFlowFunc(("NID=0x%x (%RU8)\n", uNID, uNID));
-
-    if (   !pThis->fInReset
-        && (   uNID != STAC9220_NID_ROOT
-            && uNID != STAC9220_NID_AFG)
-       )
-    {
-        RT_ZERO(pNode->node);
-    }
 
-    /* Set common parameters across all nodes. */
-    pNode->node.uID = uNID;
-    pNode->node.uSD = 0;
 
-    switch (uNID)
+static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t nodenum, PCODECNODE pNode)
+{
+    pNode->node.id = nodenum;
+    pNode->node.au32F00_param[0xF] = 0; /* Power statest Supported: are the same as AFG reports */
+    switch (nodenum)
     {
-        /* Root node. */
-        case STAC9220_NID_ROOT:
-        {
-            /* Set the revision ID. */
-            pNode->root.node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x3, 0x4, 0x0, 0x1);
+        /* Root Node*/
+        case 0:
+            pNode->node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */
             break;
-        }
-
-        /*
-         * AFG (Audio Function Group).
-         */
-        case STAC9220_NID_AFG:
-        {
-            pNode->afg.node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
-            /* We set the AFG's PCM capabitilies fixed to 44.1kHz, 16-bit signed. */
-            pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
-            pNode->afg.node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
-            pNode->afg.node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
-                                                | CODEC_F00_0C_CAP_BALANCED_IO
-                                                | CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_OUTPUT
-                                                | CODEC_F00_0C_CAP_PRESENCE_DETECT
-                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
-                                                | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;
-
-            /* Default input amplifier capabilities. */
-            pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
-                                                                CODEC_AMP_STEP_SIZE,
-                                                                CODEC_AMP_NUM_STEPS,
-                                                                CODEC_AMP_OFF_INITIAL);
-            /* Default output amplifier capabilities. */
-            pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
-                                                                CODEC_AMP_STEP_SIZE,
-                                                                CODEC_AMP_NUM_STEPS,
-                                                                CODEC_AMP_OFF_INITIAL);
-
-            pNode->afg.node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);
-            pNode->afg.node.au32F00_param[0x0F] = CODEC_F00_0F_D3
-                                                | CODEC_F00_0F_D2
-                                                | CODEC_F00_0F_D1
-                                                | CODEC_F00_0F_D0;
-
-            pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2); /* PS-Act: D2, PS->Set D2. */
+        case 1:
+            pNode->node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
+            pNode->node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
+                                            | CODEC_F00_0C_CAP_BALANCED_IO
+                                            | CODEC_F00_0C_CAP_INPUT
+                                            | CODEC_F00_0C_CAP_PRESENSE_DETECT
+                                            | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+                                            | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//(17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0);
+            pNode->node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
+            pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(1, 0x5, 0xE, 0);//RT_BIT(31)|(0x5 << 16)|(0xE)<<8;
+            pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f;
+            pNode->node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);//0xc0000004;
+            pNode->node.au32F00_param[0x0F] = CODEC_F00_0F_D3|CODEC_F00_0F_D2|CODEC_F00_0F_D1|CODEC_F00_0F_D0;
+            pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2);//0x2 << 4| 0x2; /* PS-Act: D3, PS->Set D3  */
             pNode->afg.u32F08_param = 0;
             pNode->afg.u32F17_param = 0;
             break;
-        }
-
-        /*
-         * DACs.
-         */
-        case STAC9220_NID_DAC0: /* DAC0: Headphones 0 + 1 */
-        case STAC9220_NID_DAC1: /* DAC1: PIN C */
-        case STAC9220_NID_DAC2: /* DAC2: PIN B */
-        case STAC9220_NID_DAC3: /* DAC3: PIN F */
-        {
-            pNode->dac.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
-                                                 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
-                                                 HDA_SDFMT_CHAN_STEREO);
-
-            /* 7.3.4.6: Audio widget capabilities. */
-            pNode->dac.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 13, 0)
-                                               | CODEC_F00_09_CAP_L_R_SWAP
-                                               | CODEC_F00_09_CAP_POWER_CTRL
-                                               | CODEC_F00_09_CAP_OUT_AMP_PRESENT
-                                               | CODEC_F00_09_CAP_STEREO;
-
-            /* Connection list; must be 0 if the only connection for the widget is
-             * to the High Definition Audio Link. */
-            pNode->dac.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 0 /* Entries */);
-
-            pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);
-
-            RT_ZERO(pNode->dac.B_params);
-            AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT,  0) = 0x7F | RT_BIT(7);
+        case 2:
+        case 3:
+        case 4:
+        case 5:
+            memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE);
+            pNode->dac.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 4)|0x1; /* 44100Hz/16bit/2ch */
+
+            AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
             AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
-            break;
-        }
 
-        /*
-         * ADCs.
-         */
-        case STAC9220_NID_ADC0: /* Analog input. */
-        {
-            pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC0;
+            pNode->dac.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0xD, 0)
+                                             | CODEC_F00_09_CAP_L_R_SWAP
+                                             | CODEC_F00_09_CAP_POWER_CTRL
+                                             | CODEC_F00_09_CAP_OUT_AMP_PRESENT
+                                             | CODEC_F00_09_CAP_LSB;//(0xD << 16) | RT_BIT(11) |  RT_BIT(10) | RT_BIT(2) | RT_BIT(0);
+            pNode->dac.u32F0c_param = 0;
+            pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3  */
+            break;
+        case 6:
+            pNode->node.au32F02_param[0] = 0x17;
             goto adc_init;
-        }
-
-        case STAC9220_NID_ADC1: /* Analog input (CD). */
-        {
-            pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC1;
-
-            /* Fall through is intentional. */
+        case 7:
+            pNode->node.au32F02_param[0] = 0x18;
         adc_init:
-
-            pNode->adc.u32A_param   = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
-                                                   HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
-                                                   HDA_SDFMT_CHAN_STEREO);
-
+            pNode->adc.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 3)|0x1; /* 44100Hz/16bit/2ch */
+            pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
             pNode->adc.u32F03_param = RT_BIT(0);
-            pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
-
-            pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
-                                               | CODEC_F00_09_CAP_POWER_CTRL
-                                               | CODEC_F00_09_CAP_CONNECTION_LIST
-                                               | CODEC_F00_09_CAP_PROC_WIDGET
-                                               | CODEC_F00_09_CAP_STEREO;
-            /* Connection list entries. */
-            pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
+            pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */
+            pNode->adc.u32F06_param = 0;
+            pNode->adc.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
+                                             | CODEC_F00_09_CAP_POWER_CTRL
+                                             | CODEC_F00_09_CAP_CONNECTION_LIST
+                                             | CODEC_F00_09_CAP_PROC_WIDGET
+                                             | CODEC_F00_09_CAP_LSB;//RT_BIT(20)| (0xd << 16) |  RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0);
             break;
-        }
-
-        /*
-         * SP/DIF In/Out.
-         */
-        case STAC9220_NID_SPDIF_OUT:
-        {
-            pNode->spdifout.u32A_param   = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
-                                                        HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
-                                                        HDA_SDFMT_CHAN_STEREO);
+        case 8:
+            pNode->spdifout.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(1<<14)|(0x1<<4) | 0x1;
+            pNode->spdifout.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x4, 0)
+                                                  | CODEC_F00_09_CAP_DIGITAL
+                                                  | CODEC_F00_09_CAP_FMT_OVERRIDE
+                                                  | CODEC_F00_09_CAP_LSB;//(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
+            pNode->node.au32F00_param[0xa] = pThis->paNodes[1].node.au32F00_param[0xA];
+            pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
             pNode->spdifout.u32F06_param = 0;
             pNode->spdifout.u32F0d_param = 0;
-
-            pNode->spdifout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 4, 0)
-                                                    | CODEC_F00_09_CAP_DIGITAL
-                                                    | CODEC_F00_09_CAP_FMT_OVERRIDE
-                                                    | CODEC_F00_09_CAP_STEREO;
-
-            /* Use a fixed format from AFG. */
-            pNode->spdifout.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
-            pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
             break;
-        }
-
-        case STAC9220_NID_SPDIF_IN:
-        {
-            pNode->spdifin.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
-                                                     HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
-                                                     HDA_SDFMT_CHAN_STEREO);
-
-            pNode->spdifin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 4, 0)
-                                                   | CODEC_F00_09_CAP_DIGITAL
-                                                   | CODEC_F00_09_CAP_CONNECTION_LIST
-                                                   | CODEC_F00_09_CAP_FMT_OVERRIDE
-                                                   | CODEC_F00_09_CAP_STEREO;
-
-            /* Use a fixed format from AFG. */
-            pNode->spdifin.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
+        case 9:
+            pNode->spdifin.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(0x1<<4) | 0x1;
+            pNode->spdifin.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0x4, 0)
+                                                 | CODEC_F00_09_CAP_DIGITAL
+                                                 | CODEC_F00_09_CAP_CONNECTION_LIST
+                                                 | CODEC_F00_09_CAP_FMT_OVERRIDE
+                                                 | CODEC_F00_09_CAP_LSB;//(0x1 << 20)|(4 << 16) | RT_BIT(9)| RT_BIT(8)|RT_BIT(4)|0x1;
+            pNode->node.au32F00_param[0xA] = pThis->paNodes[1].node.au32F00_param[0xA];
+            pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
+            pNode->node.au32F02_param[0] = 0x11;
             pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
-
-            /* Connection list entries. */
-            pNode->spdifin.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
-            pNode->spdifin.node.au32F02_param[0]   = 0x11;
+            pNode->spdifin.u32F06_param = 0;
+            pNode->spdifin.u32F0d_param = 0;
             break;
-        }
-
-        /*
-         * PINs / Ports.
-         */
-        case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
-        {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
-            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
-                                                | CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_OUTPUT
-                                                | CODEC_F00_0C_CAP_HEADPHONE_AMP
-                                                | CODEC_F00_0C_CAP_PRESENCE_DETECT
-                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
-            /* Connection list entry 0: Goes to DAC0. */
-            pNode->port.node.au32F02_param[0]   = STAC9220_NID_DAC0;
-
+        case 0xA:
+            pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+                                           | CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_OUTPUT
+                                           | CODEC_F00_0C_CAP_HP
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT
+                                           | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+                                           | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x173f;
+            pNode->node.au32F02_param[0] = 0x2;
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
+                                     | CODEC_F07_OUT_ENABLE;
+            pNode->port.u32F08_param = 0;
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                           CODEC_F1C_LOCATION_FRONT,
                                                           CODEC_F1C_DEVICE_HP,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_GREEN,
-                                                          CODEC_F1C_MISC_NONE,
-                                                          CODEC_F1C_ASSOCIATION_GROUP_1, 0x0 /* Seq */);
+                                                          CODEC_F1C_MISC_JACK_DETECT,
+                                                          0x2, 0);//RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
             goto port_init;
-        }
-
-        case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
-        {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
-            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
-                                                | CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_OUTPUT
-                                                | CODEC_F00_0C_CAP_PRESENCE_DETECT
-                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
-            /* Connection list entry 0: Goes to DAC2. */
-            pNode->port.node.au32F02_param[0]   = STAC9220_NID_DAC2;
-
+        case 0xB:
+            pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+                                           | CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_OUTPUT
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT
+                                           | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+                                           | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
+            pNode->node.au32F02_param[0] = 0x4;
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
-                                                          CODEC_F1C_LOCATION_REAR,
+                                                          CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR,
                                                           CODEC_F1C_DEVICE_SPEAKER,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_BLACK,
-                                                          CODEC_F1C_MISC_NONE,
-                                                          CODEC_F1C_ASSOCIATION_GROUP_0, 0x1 /* Seq */);
+                                                          CODEC_F1C_MISC_JACK_DETECT,
+                                                          0x1, 0x1);//RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
             goto port_init;
-        }
-
-        case STAC9220_NID_PIN_C: /* Rear Speaker. */
-        {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
-            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
-                                                | CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_OUTPUT
-                                                | CODEC_F00_0C_CAP_PRESENCE_DETECT
-                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
-            /* Connection list entry 0: Goes to DAC1. */
-            pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC1;
-
+        case 0xC:
+            pNode->node.au32F02_param[0] = 0x3;
+            pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+                                           | CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_OUTPUT
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT
+                                           | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+                                           | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                           CODEC_F1C_LOCATION_REAR,
                                                           CODEC_F1C_DEVICE_SPEAKER,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_GREEN,
-                                                          CODEC_F1C_MISC_NONE,
-                                                          CODEC_F1C_ASSOCIATION_GROUP_0, 0x0 /* Seq */);
+                                                          0x0, 0x1, 0x0);//RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
             goto port_init;
-        }
-
-        case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
-        {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
-            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
-                                                | CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_OUTPUT
-                                                | CODEC_F00_0C_CAP_HEADPHONE_AMP
-                                                | CODEC_F00_0C_CAP_PRESENCE_DETECT
-                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
-            /* Connection list entry 0: Goes to DAC1. */
-            pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC0;
-
+        case 0xD:
+            pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+                                           | CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_OUTPUT
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT
+                                           | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+                                           | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
+            pNode->node.au32F02_param[0] = 0x2;
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                           CODEC_F1C_LOCATION_FRONT,
                                                           CODEC_F1C_DEVICE_MIC,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_PINK,
-                                                          CODEC_F1C_MISC_NONE,
-                                                          CODEC_F1C_ASSOCIATION_GROUP_4, 0x0 /* Seq */);
-            /* Fall through is intentional. */
-
+                                                          0x0, 0x5, 0x0);//RT_MAKE_U32_FROM_U8(0x50, 0x90, 0xA1, 0x02); /* Microphone */
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
         port_init:
-
-            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
-                                     | CODEC_F07_OUT_ENABLE;
             pNode->port.u32F08_param = 0;
-
-            pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
-                                                | CODEC_F00_09_CAP_CONNECTION_LIST
-                                                | CODEC_F00_09_CAP_UNSOL
-                                                | CODEC_F00_09_CAP_STEREO;
-            /* Connection list entries. */
-            pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
+            pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
+                                         | CODEC_F00_09_CAP_CONNECTION_LIST
+                                         | CODEC_F00_09_CAP_UNSOL
+                                         | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
+            pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
             break;
-        }
-
-        case STAC9220_NID_PIN_E:
-        {
-            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
+        case 0xE:
+            pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
+                                         | CODEC_F00_09_CAP_UNSOL
+                                         | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(7)|RT_BIT(0);
             pNode->port.u32F08_param = 0;
-            /* If Line in is reported as enabled, OS X sees no speakers! Windows does
-             * not care either way, although Linux does.
-             */
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, 0);
-
-            pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
-                                                | CODEC_F00_09_CAP_UNSOL
-                                                | CODEC_F00_09_CAP_STEREO;
-
-            pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_PRESENCE_DETECT;
-
+            pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_OUTPUT
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT;//0x34;
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                           CODEC_F1C_LOCATION_REAR,
-                                                          CODEC_F1C_DEVICE_LINE_IN,
+                                                          CODEC_F1C_DEVICE_LINE_OUT,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_BLUE,
-                                                          CODEC_F1C_MISC_NONE,
-                                                          CODEC_F1C_ASSOCIATION_GROUP_4, 0x1 /* Seq */);
+                                                          0x0, 0x4, 0x0);//0x01013040;  /* Line Out */
             break;
-        }
-
-        case STAC9220_NID_PIN_F:
-        {
-            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE | CODEC_F07_OUT_ENABLE;
+        case 0xF:
+            pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
+                                         | CODEC_F00_09_CAP_CONNECTION_LIST
+                                         | CODEC_F00_09_CAP_UNSOL
+                                         | CODEC_F00_09_CAP_OUT_AMP_PRESENT
+                                         | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(2)|RT_BIT(0);
+            pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_OUTPUT
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT
+                                           /* | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+                                           | CODEC_F00_0C_CAP_IMPENDANCE_SENSE */;//0x37;
+            pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
             pNode->port.u32F08_param = 0;
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /* fPresent */, CODEC_F09_ANALOG_NA);
-
-            pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
-                                                | CODEC_F00_09_CAP_CONNECTION_LIST
-                                                | CODEC_F00_09_CAP_UNSOL
-                                                | CODEC_F00_09_CAP_OUT_AMP_PRESENT
-                                                | CODEC_F00_09_CAP_STEREO;
-
-            pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
-                                                | CODEC_F00_0C_CAP_OUTPUT;
-
-            /* Connection list entry 0: Goes to DAC3. */
-            pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
-            pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC3;
-
+            pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE
+                                     | CODEC_F07_IN_ENABLE;
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                           CODEC_F1C_LOCATION_INTERNAL,
                                                           CODEC_F1C_DEVICE_SPEAKER,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_ORANGE,
-                                                          CODEC_F1C_MISC_NONE,
-                                                          CODEC_F1C_ASSOCIATION_GROUP_0, 0x2 /* Seq */);
+                                                          0x0, 0x1, 0x2);//RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01);
+            pNode->node.au32F02_param[0] = 0x5;
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
             break;
-        }
-
-        case STAC9220_NID_PIN_SPDIF_OUT: /* Rear SPDIF Out. */
-        {
-            pNode->digout.u32F07_param = CODEC_F07_OUT_ENABLE;
-            pNode->digout.u32F09_param = 0;
-
-            pNode->digout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
-                                                  | CODEC_F00_09_CAP_DIGITAL
-                                                  | CODEC_F00_09_CAP_CONNECTION_LIST
-                                                  | CODEC_F00_09_CAP_STEREO;
-            pNode->digout.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT
-                                                  | CODEC_F00_0C_CAP_PRESENCE_DETECT;
-
-            /* Connection list entries. */
-            pNode->digout.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 3 /* Entries */);
-            pNode->digout.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_SPDIF_OUT,
-                                                                        STAC9220_NID_AMP_ADC0, STAC9221_NID_ADAT_OUT, 0);
+        case 0x10:
+            pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
+                                         | CODEC_F00_09_CAP_DIGITAL
+                                         | CODEC_F00_09_CAP_CONNECTION_LIST
+                                         | CODEC_F00_09_CAP_LSB;//(4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
+            pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//RT_BIT(4);
+            pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x3);
+            pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0);
             if (!pThis->fInReset)
                 pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                             CODEC_F1C_LOCATION_REAR,
                                                             CODEC_F1C_DEVICE_SPDIF_OUT,
                                                             CODEC_F1C_CONNECTION_TYPE_DIN,
                                                             CODEC_F1C_COLOR_BLACK,
-                                                            CODEC_F1C_MISC_NONE,
-                                                            CODEC_F1C_ASSOCIATION_GROUP_2, 0x0 /* Seq */);
+                                                            0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
             break;
-        }
-
-        case STAC9220_NID_PIN_SPDIF_IN:
-        {
-            pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 -> D3 */
-            pNode->digin.u32F07_param = CODEC_F07_IN_ENABLE;
+        case 0x11:
+            pNode->node.au32F00_param[9] = (4 << 20) | (3 << 16) | RT_BIT(10) | RT_BIT(9) | RT_BIT(7) | RT_BIT(0);
+            pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
+                                           | CODEC_F00_0C_CAP_INPUT
+                                           | CODEC_F00_0C_CAP_PRESENSE_DETECT;//RT_BIT(16)| RT_BIT(5)|RT_BIT(2);
+            pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */
+            pNode->digin.u32F07_param = 0;
             pNode->digin.u32F08_param = 0;
             pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
             pNode->digin.u32F0c_param = 0;
-
-            pNode->digin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 3, 0)
-                                                 | CODEC_F00_09_CAP_POWER_CTRL
-                                                 | CODEC_F00_09_CAP_DIGITAL
-                                                 | CODEC_F00_09_CAP_UNSOL
-                                                 | CODEC_F00_09_CAP_STEREO;
-
-            pNode->digin.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
-                                                 | CODEC_F00_0C_CAP_INPUT
-                                                 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
             if (!pThis->fInReset)
                 pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                            CODEC_F1C_LOCATION_REAR,
                                                            CODEC_F1C_DEVICE_SPDIF_IN,
                                                            CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
                                                            CODEC_F1C_COLOR_BLACK,
-                                                           CODEC_F1C_MISC_NONE,
-                                                           CODEC_F1C_ASSOCIATION_GROUP_5, 0x0 /* Seq */);
+                                                           0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60;
             break;
-        }
-
-        case STAC9220_NID_ADC0_MUX:
-        {
-            pNode->adcmux.u32F01_param = 0; /* Connection select control index (STAC9220_NID_PIN_E). */
+        case 0x12:
+            pNode->adcmux.u32F01_param = 0;
             goto adcmux_init;
-        }
-
-        case STAC9220_NID_ADC1_MUX:
-        {
-            pNode->adcmux.u32F01_param = 1; /* Connection select control index (STAC9220_NID_PIN_CD). */
-            /* Fall through is intentional. */
-
-        adcmux_init:
-
-            pNode->adcmux.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
-                                                  | CODEC_F00_09_CAP_CONNECTION_LIST
-                                                  | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
-                                                  | CODEC_F00_09_CAP_OUT_AMP_PRESENT
-                                                  | CODEC_F00_09_CAP_STEREO;
-
-            pNode->adcmux.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 27, 4, 0);
-
-            /* Connection list entries. */
-            pNode->adcmux.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 7 /* Entries */);
-            pNode->adcmux.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_E,
-                                                                        STAC9220_NID_PIN_CD,
-                                                                        STAC9220_NID_PIN_F,
-                                                                        STAC9220_NID_PIN_B);
-            pNode->adcmux.node.au32F02_param[0x4] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_C,
-                                                                        STAC9220_NID_PIN_HEADPHONE1,
-                                                                        STAC9220_NID_PIN_HEADPHONE0,
-                                                                        0x0 /* Unused */);
-
-            /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplifiers initialized with 0. */
-            RT_ZERO(pNode->adcmux.B_params);
+        case 0x13:
+            pNode->adcmux.u32F01_param = 1;
+            adcmux_init:
+            pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0x0, 0)
+                                         | CODEC_F00_09_CAP_CONNECTION_LIST
+                                         | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
+                                         | CODEC_F00_09_CAP_OUT_AMP_PRESENT
+                                         | CODEC_F00_09_CAP_LSB;//(3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0);
+            pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x7);
+            pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8);
+            /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/
+            memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE);
+            pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb);
+            pNode->node.au32F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0);
             break;
-        }
-
-        case STAC9220_NID_PCBEEP:
-        {
+        case 0x14:
+            pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
+                                         | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
+                                         | CODEC_F00_09_CAP_OUT_AMP_PRESENT;//(7 << 20) | RT_BIT(3) | RT_BIT(2);
+            pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3;
             pNode->pcbeep.u32F0a_param = 0;
-
-            pNode->pcbeep.node.au32F00_param[0x9]  = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
-                                                   | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
-                                                   | CODEC_F00_09_CAP_OUT_AMP_PRESENT;
-            pNode->pcbeep.node.au32F00_param[0xD]  = CODEC_MAKE_F00_0D(0, 17, 3, 3);
-
-            RT_ZERO(pNode->pcbeep.B_params);
+            memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
             break;
-        }
-
-        case STAC9220_NID_PIN_CD:
-        {
-            pNode->cdnode.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
-                                                  | CODEC_F00_09_CAP_STEREO;
-            pNode->cdnode.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT;
-
+        case 0x15:
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
+                                           | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(0);
+            pNode->node.au32F00_param[0xc] = CODEC_F00_0C_CAP_INPUT;//RT_BIT(5);
             if (!pThis->fInReset)
                 pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
                                                             CODEC_F1C_LOCATION_INTERNAL,
                                                             CODEC_F1C_DEVICE_CD,
                                                             CODEC_F1C_CONNECTION_TYPE_ATAPI,
                                                             CODEC_F1C_COLOR_UNKNOWN,
-                                                            CODEC_F1C_MISC_NONE,
-                                                            CODEC_F1C_ASSOCIATION_GROUP_4, 0x2 /* Seq */);
+                                                            0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90);
             break;
-        }
-
-        case STAC9220_NID_VOL_KNOB:
-        {
+        case 0x16:
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0x0, 0x0);//(0x6 << 20);
+            pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F;
+            pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x4);
+            pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5);
             pNode->volumeKnob.u32F08_param = 0;
             pNode->volumeKnob.u32F0f_param = 0x7f;
-
-            pNode->volumeKnob.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0, 0);
-            pNode->volumeKnob.node.au32F00_param[0xD] = RT_BIT(7) | 0x7F;
-
-            /* Connection list entries. */
-            pNode->volumeKnob.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 4 /* Entries */);
-            pNode->volumeKnob.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_DAC0,
-                                                                            STAC9220_NID_DAC1,
-                                                                            STAC9220_NID_DAC2,
-                                                                            STAC9220_NID_DAC3);
             break;
-        }
-
-        case STAC9220_NID_AMP_ADC0: /* ADC0Vol */
-        {
-            pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC0_MUX;
+        case 0x17:
+            pNode->node.au32F02_param[0] = 0x12;
             goto adcvol_init;
-        }
-
-        case STAC9220_NID_AMP_ADC1: /* ADC1Vol */
-        {
-            pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC1_MUX;
-            /* Fall through is intentional. */
-
+        case 0x18:
+            pNode->node.au32F02_param[0] = 0x13;
         adcvol_init:
+            memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
 
-            pNode->adcvol.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
-                                                  | CODEC_F00_09_CAP_L_R_SWAP
-                                                  | CODEC_F00_09_CAP_CONNECTION_LIST
-                                                  | CODEC_F00_09_CAP_IN_AMP_PRESENT
-                                                  | CODEC_F00_09_CAP_STEREO;
-
-
-            pNode->adcvol.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
-
-            RT_ZERO(pNode->adcvol.B_params);
-            AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT,  0) = RT_BIT(7);
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
+                                           | CODEC_F00_09_CAP_L_R_SWAP
+                                           | CODEC_F00_09_CAP_CONNECTION_LIST
+                                           | CODEC_F00_09_CAP_IN_AMP_PRESENT
+                                           | CODEC_F00_09_CAP_LSB;//(0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0);
+            pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x1);
+            AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
             AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
+            pNode->adcvol.u32F0c_param = 0;
             break;
-        }
-
-        /*
-         * STAC9221 nodes.
-         */
-
-        case STAC9221_NID_ADAT_OUT:
-        {
-            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 3, 0)
+        case 0x19:
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0)
                                            | CODEC_F00_09_CAP_DIGITAL
-                                           | CODEC_F00_09_CAP_STEREO;
+                                           | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
             break;
-        }
-
-        case STAC9221_NID_I2S_OUT:
-        {
-            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 3, 0)
+        case 0x1A:
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0)
                                            | CODEC_F00_09_CAP_DIGITAL
-                                           | CODEC_F00_09_CAP_STEREO;
+                                           | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
             break;
-        }
-
-        case STAC9221_NID_PIN_I2S_OUT:
-        {
+        case 0x1B:
             pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
                                            | CODEC_F00_09_CAP_DIGITAL
                                            | CODEC_F00_09_CAP_CONNECTION_LIST
-                                           | CODEC_F00_09_CAP_STEREO;
-
-            pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
-
-            /* Connection list entries. */
-            pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
-            pNode->node.au32F02_param[0]   = STAC9221_NID_I2S_OUT;
-
-            if (!pThis->fInReset)
-                pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
-                                                              CODEC_F1C_LOCATION_NA,
-                                                              CODEC_F1C_DEVICE_LINE_OUT,
-                                                              CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
-                                                              CODEC_F1C_COLOR_UNKNOWN,
-                                                              CODEC_F1C_MISC_NONE,
-                                                              CODEC_F1C_ASSOCIATION_GROUP_15, 0xB /* Seq */);
+                                           | CODEC_F00_09_CAP_LSB;//(0x4 << 20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
+            pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x1);
+            pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//0x10;
+            pNode->node.au32F02_param[0] = 0x1a;
+            pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
+                                                          CODEC_F1C_LOCATION_NA,
+                                                          CODEC_F1C_DEVICE_LINE_OUT,
+                                                          CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
+                                                          CODEC_F1C_COLOR_UNKNOWN,
+                                                          0x0, 0x0, 0xf);//0x4000000f;
             break;
-        }
-
         default:
-            AssertMsgFailed(("Node %RU8 not implemented\n", uNID));
-            break;
+        break;
     }
-
     return VINF_SUCCESS;
 }
 
+
 static int stac9220Construct(PHDACODEC pThis)
 {
-    unconst(pThis->cTotalNodes) = STAC9221_NUM_NODES;
-
+    unconst(pThis->cTotalNodes) = 0x1C;
     pThis->pfnCodecNodeReset = stac9220ResetNode;
-
-    pThis->u16VendorId  = 0x8384; /* SigmaTel */
-    /*
-     * Note: The Linux kernel uses "patch_stac922x" for the fixups,
-     *       which in turn uses "ref922x_pin_configs" for the configuration
-     *       defaults tweaking in sound/pci/hda/patch_sigmatel.c.
-     */
-    pThis->u16DeviceId  = 0x7680; /* STAC9221 A1 */
-    pThis->u8BSKU       = 0x76;
+    pThis->pfnDbgListNodes   = stac9220DbgNodes;
+    pThis->u16VendorId = 0x8384;
+    pThis->u16DeviceId = 0x7680;
+    pThis->u8BSKU = 0x76;
     pThis->u8AssemblyId = 0x80;
-
     pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes);
     if (!pThis->paNodes)
         return VERR_NO_MEMORY;
-
     pThis->fInReset = false;
-
 #define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s
     STAC9220WIDGET(Port);
     STAC9220WIDGET(Dac);
@@ -1486,9 +1239,8 @@ static int stac9220Construct(PHDACODEC pThis)
     STAC9220WIDGET(VolKnob);
     STAC9220WIDGET(Reserved);
 #undef STAC9220WIDGET
-
-    unconst(pThis->u8AdcVolsLineIn) = STAC9220_NID_AMP_ADC0;
-    unconst(pThis->u8DacLineOut)    = STAC9220_NID_DAC1;
+    unconst(pThis->u8AdcVolsLineIn) = 0x17;
+    unconst(pThis->u8DacLineOut) = 0x3;
 
     return VINF_SUCCESS;
 }
@@ -1498,14 +1250,14 @@ static int stac9220Construct(PHDACODEC pThis)
  * Some generic predicate functions.
  */
 
-#define DECLISNODEOFTYPE(type)                                              \
-    DECLINLINE(bool) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
-    {                                                                       \
-        Assert(pThis->au8##type##s);                                        \
-        for (int i = 0; pThis->au8##type##s[i] != 0; ++i)                   \
-            if (pThis->au8##type##s[i] == cNode)                            \
-                return true;                                                \
-        return false;                                                       \
+#define DECLISNODEOFTYPE(type)                                                                  \
+    DECLINLINE(int) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode)                     \
+    {                                                                                           \
+        Assert(pThis->au8##type##s);                                                           \
+        for (int i = 0; pThis->au8##type##s[i] != 0; ++i)                                      \
+            if (pThis->au8##type##s[i] == cNode)                                               \
+                return 1;                                                                       \
+        return 0;                                                                               \
     }
 /* hdaCodecIsPortNode */
 DECLISNODEOFTYPE(Port)
@@ -1538,35 +1290,33 @@ DECLISNODEOFTYPE(Reserved)
 /*
  * Misc helpers.
  */
-static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
+static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL mt)
 {
-    uint8_t iDir;
-    switch (enmMixerCtl)
+    uint32_t dir = AMPLIFIER_OUT;
+    ENMSOUNDSOURCE enmSrc;
+    switch (mt)
     {
-        case PDMAUDIOMIXERCTL_VOLUME_MASTER:
-        case PDMAUDIOMIXERCTL_FRONT:
-            iDir = AMPLIFIER_OUT;
+        case PDMAUDIOMIXERCTL_PCM:
+            enmSrc = PO_INDEX;
+            dir = AMPLIFIER_OUT;
             break;
         case PDMAUDIOMIXERCTL_LINE_IN:
-        case PDMAUDIOMIXERCTL_MIC_IN:
-            iDir = AMPLIFIER_IN;
+            enmSrc = PI_INDEX;
+            dir = AMPLIFIER_IN;
             break;
         default:
-            AssertMsgFailedReturn(("Invalid mixer control %d\n", enmMixerCtl), VERR_INVALID_PARAMETER);
+            AssertMsgFailedReturn(("Invalid mixer control %ld\n", mt), VERR_INVALID_PARAMETER);
             break;
     }
 
-    int iMute;
-    iMute  = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT,  0) & RT_BIT(7);
-    iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
-    iMute >>=7;
-    iMute &= 0x1;
-
-    uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT,  0) & 0x7f;
-    uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
+    int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
+    mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
+    mute >>=7;
+    mute &= 0x1;
+    uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f;
+    uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f;
 
-    /*
-     * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
+    /* The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
      * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
      * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
      * to 1 (rather than zero) internally.
@@ -1574,8 +1324,7 @@ static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCT
     lVol = (lVol + 1) * (2 * 255) / 256;
     rVol = (rVol + 1) * (2 * 255) / 256;
 
-    PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
-    return pThis->pfnMixerSetVolume(pThis->pHDAState, enmMixerCtl, &Vol);
+    return pThis->pfnSetVolume(pThis->pHDAState, enmSrc, RT_BOOL(mute), lVol, rVol);
 }
 
 DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
@@ -1599,7 +1348,6 @@ DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint
 /*
  * Verb processor functions.
  */
-#if 0 /* unused */
 
 static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
@@ -1610,6 +1358,7 @@ static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uin
     return VINF_SUCCESS;
 }
 
+#if 0 // unused
 static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
     int rc;
@@ -1617,17 +1366,22 @@ static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *p
     *pResp |= CODEC_RESPONSE_UNSOLICITED;
     return rc;
 }
-
-#endif /* unused */
+#endif
 
 /* B-- */
 static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     /* HDA spec 7.3.3.7 Note A */
-    /** @todo If index out of range response should be 0. */
-    uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(cmd);
+    /** @todo: if index out of range response should be 0 */
+    uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd);
 
     PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
     if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
@@ -1661,18 +1415,27 @@ static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
                             CODEC_GET_AMP_SIDE(cmd),
                             u8Index);
     else
-        LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd), CODEC_NID(cmd)));
-
+        AssertMsgFailedReturn(("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS);
     return VINF_SUCCESS;
 }
 
 /* 3-- */
 static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    bool fIsLeft = false;
+    bool fIsRight = false;
+    bool fIsOut = false;
+    bool fIsIn = false;
+    uint8_t u8Index = 0;
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    PCODECNODE pNode      = &pThis->paNodes[CODEC_NID(cmd)];
-    AMPLIFIER *pAmplifier = NULL;
+    PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
+    AMPLIFIER *pAmplifier;
     if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
         pAmplifier = &pNode->dac.B_params;
     else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
@@ -1686,22 +1449,16 @@ static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
     else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
         pAmplifier = &pNode->adc.B_params;
     else
-        LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd), CODEC_NID(cmd)));
-
-    if (!pAmplifier)
-        return VINF_SUCCESS;
-
-    bool fIsOut     = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
-    bool fIsIn      = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
-    bool fIsRight   = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
-    bool fIsLeft    = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
-    uint8_t u8Index = CODEC_SET_AMP_INDEX(cmd);
+        AssertFailedReturn(VINF_SUCCESS);
 
+    fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
+    fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
+    fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
+    fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
+    u8Index = CODEC_SET_AMP_INDEX(cmd);
     if (   (!fIsLeft && !fIsRight)
         || (!fIsOut && !fIsIn))
         return VINF_SUCCESS;
-
     if (fIsIn)
     {
         if (fIsLeft)
@@ -1720,7 +1477,7 @@ static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
             hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
 
         if (CODEC_NID(cmd) == pThis->u8DacLineOut)
-            hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
+            hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_PCM);
     }
 
     return VINF_SUCCESS;
@@ -1728,15 +1485,18 @@ static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
 
 static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
     if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
     {
-        *pResp = 0;
-
         LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
         return VINF_SUCCESS;
     }
-
     *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
     return VINF_SUCCESS;
 }
@@ -1744,8 +1504,14 @@ static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint
 /* F01 */
 static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
     else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -1756,18 +1522,20 @@ static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd,
         *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
     else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
 /* 701 */
 static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    uint32_t *pu32Reg = NULL;
+    uint32_t *pu32Reg;
     if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
     else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -1779,19 +1547,22 @@ static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd,
     else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
     else
-        LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    if (pu32Reg)
-        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+        AssertFailedReturn(VINF_SUCCESS);
+    hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
     return VINF_SUCCESS;
 }
 
 /* F07 */
 static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
     else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -1805,17 +1576,22 @@ static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64
     else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
     else
-        LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+        AssertMsgFailed(("Unsupported"));
     return VINF_SUCCESS;
 }
 
 /* 707 */
 static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    uint32_t *pu32Reg = NULL;
+    uint32_t *pu32Reg;
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
@@ -1830,24 +1606,27 @@ static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64
              && CODEC_NID(cmd) == 0x1b)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
     else
-        LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    if (pu32Reg)
-        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+        AssertFailedReturn(VINF_SUCCESS);
+    hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
     return VINF_SUCCESS;
 }
 
 /* F08 */
 static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
-    else if ((cmd) == STAC9220_NID_AFG)
+    else if ((cmd) == 1 /* AFG */)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
     else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
@@ -1856,22 +1635,27 @@ static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
     else
-        LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+        AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
     return VINF_SUCCESS;
 }
 
 /* 708 */
 static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    uint32_t *pu32Reg = NULL;
+    uint32_t *pu32Reg;
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
-    else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    else if (CODEC_NID(cmd) == 1 /* AFG */)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
     else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
@@ -1880,55 +1664,63 @@ static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t
     else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
     else
-        LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    if (pu32Reg)
-        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+        AssertMsgFailedReturn(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)), VINF_SUCCESS);
+    hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
     return VINF_SUCCESS;
 }
 
 /* F09 */
 static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
     else
-    {
-        AssertFailed();
-        LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-    }
-
+        AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
     return VINF_SUCCESS;
 }
 
 /* 709 */
 static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    uint32_t *pu32Reg = NULL;
+    uint32_t *pu32Reg;
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
     else
-        LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    if (pu32Reg)
-        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+        AssertFailedReturn(VINF_SUCCESS);
+    hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
     return VINF_SUCCESS;
 }
 
 static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
     *pResp = 0;
-
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
     if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
     {
@@ -1942,19 +1734,30 @@ static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t
 /* F03 */
 static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param;
-
     return VINF_SUCCESS;
 }
 
 /* 703 */
 static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
         hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
     return VINF_SUCCESS;
@@ -1963,20 +1766,31 @@ static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd
 /* F0D */
 static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
     else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
-
     return VINF_SUCCESS;
 }
 
 static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
         hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
     else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
@@ -2006,7 +1820,7 @@ static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t
         LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
         return VINF_SUCCESS;
     }
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    if (CODEC_NID(cmd) == 1 /* AFG */)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
     else
         *pResp = 0;
@@ -2023,7 +1837,7 @@ static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
         return VINF_SUCCESS;
     }
     uint32_t *pu32Reg;
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    if (CODEC_NID(cmd) == 0x1 /* AFG */)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
     else
         AssertFailedReturn(VINF_SUCCESS);
@@ -2062,23 +1876,20 @@ static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_
 static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
     Assert(CODEC_CAD(cmd) == pThis->id);
-    Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
-
-    if (   CODEC_NID(cmd) == STAC9220_NID_AFG
+    Assert(CODEC_NID(cmd) == 1 /* AFG */);
+    if (   CODEC_NID(cmd) == 1 /* AFG */
         && pThis->pfnCodecNodeReset)
     {
-        LogFunc(("Entering reset ...\n"));
-
-        pThis->fInReset = true;
-
-        for (uint8_t i = 0; i < pThis->cTotalNodes; ++i)
+        uint8_t i;
+        LogFlowFunc(("enters reset\n"));
+        Assert(pThis->pfnCodecNodeReset);
+        for (i = 0; i < pThis->cTotalNodes; ++i)
+        {
             pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
-
+        }
         pThis->fInReset = false;
-
-        LogFunc(("Exited reset\n"));
+        LogFlowFunc(("exits reset\n"));
     }
-
     *pResp = 0;
     return VINF_SUCCESS;
 }
@@ -2086,126 +1897,33 @@ static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *p
 /* F05 */
 static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    if (CODEC_NID(cmd) == 1 /* AFG */)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
     else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
-    else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
-        *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
-    else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
-        *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
+    else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
+        *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
     else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
     else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
     else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
-             CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_ACT(*pResp), CODEC_F05_SET(*pResp)));
     return VINF_SUCCESS;
 }
 
 /* 705 */
-#if 1
-static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    *pResp = 0;
-
-    uint32_t *pu32Reg = NULL;
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
-    else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
-    else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
-    else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
-    else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
-    else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
-    else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
-    else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
-    else
-    {
-        AssertFailed();
-        LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-    }
-
-    if (!pu32Reg)
-        return VINF_SUCCESS;
-
-    uint8_t uPwrCmd = CODEC_F05_SET      (cmd);
-    bool    fReset  = CODEC_F05_IS_RESET (*pu32Reg);
-    bool    fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
-#ifdef LOG_ENABLED
-    bool    fError  = CODEC_F05_IS_ERROR (*pu32Reg);
-    uint8_t uPwrAct = CODEC_F05_ACT      (*pu32Reg);
-    uint8_t uPwrSet = CODEC_F05_SET      (*pu32Reg);
-    LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
-             CODEC_NID(cmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
-    LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
-            CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param),
-            CODEC_F05_SET(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param)));
-#endif
-
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
-        *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
-
-    const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param);
-    if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
-    {
-        /* Propagate to all other nodes under this AFG. */
-        LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
-
-#define PROPAGATE_PWR_STATE(_aList, _aMember) \
-        { \
-            const uint8_t *pu8NodeIndex = &_aList[0]; \
-            while (*(++pu8NodeIndex)) \
-            { \
-                pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param = \
-                    CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
-                LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", *pu8NodeIndex, \
-                         CODEC_F05_ACT(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param), \
-                         CODEC_F05_SET(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param))); \
-            } \
-        }
-
-        PROPAGATE_PWR_STATE(pThis->au8Dacs,       dac);
-        PROPAGATE_PWR_STATE(pThis->au8Adcs,       adc);
-        PROPAGATE_PWR_STATE(pThis->au8DigInPins,  digin);
-        PROPAGATE_PWR_STATE(pThis->au8DigOutPins, digout);
-        PROPAGATE_PWR_STATE(pThis->au8SpdifIns,   spdifin);
-        PROPAGATE_PWR_STATE(pThis->au8SpdifOuts,  spdifout);
-        PROPAGATE_PWR_STATE(pThis->au8Reserveds,  reserved);
-
-#undef PROPAGATE_PWR_STATE
-    }
-    /*
-     * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
-     * as PS-Set of this node. PS-Act always is one level under PS-Set here.
-     */
-    else
-    {
-        *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
-    }
 
-    LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
-             CODEC_NID(cmd),
-             CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
-
-    return VINF_SUCCESS;
-}
-#else
 DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
 {
     Assert(pu32F05_param);
@@ -2282,12 +2000,17 @@ static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uin
     }
     return VINF_SUCCESS;
 }
-#endif
 
 static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
     else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
@@ -2296,94 +2019,48 @@ static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint6
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
     else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
-    else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
+    else if (CODEC_NID(cmd) == 0x1A)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
-                 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd), CODEC_F00_06_GET_CHANNEL_ID(cmd)));
-
     return VINF_SUCCESS;
 }
 
-/* F06 */
 static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
-    *pResp = 0;
-
-    PDMAUDIODIR enmDir;
-
-    uint32_t *pu32Addr = NULL;
-    if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
     {
-        pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
-        enmDir = PDMAUDIODIR_OUT;
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
     }
+    *pResp = 0;
+    uint32_t *pu32addr;
+    if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
+        pu32addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
     else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
-    {
-        pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
-        enmDir = PDMAUDIODIR_IN;
-    }
+        pu32addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
     else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
-    {
-        pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
-        enmDir = PDMAUDIODIR_OUT;
-    }
+        pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
     else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
-    {
-        pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
-        enmDir = PDMAUDIODIR_IN;
-    }
+        pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
+    else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
+        pu32addr = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
     else
-    {
-        enmDir = PDMAUDIODIR_UNKNOWN;
-        LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-    }
-
-    /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
-    if (enmDir != PDMAUDIODIR_UNKNOWN)
-    {
-        uint8_t uSD      = CODEC_F00_06_GET_STREAM_ID(cmd);
-        uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(cmd);
-
-        LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8, enmDir=%RU32\n",
-                     CODEC_NID(cmd), uSD, uChannel, enmDir));
-
-        pThis->paNodes[CODEC_NID(cmd)].node.uSD      = uSD;
-        pThis->paNodes[CODEC_NID(cmd)].node.uChannel = uChannel;
-
-        if (enmDir == PDMAUDIODIR_OUT)
-        {
-            /** @todo Check if non-interleaved streams need a different channel / SDn? */
-
-            /* Propagate to the controller. */
-            pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_FRONT,      uSD, uChannel);
-#ifdef VBOX_WITH_HDA_51_SURROUND
-            pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
-            pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_REAR,       uSD, uChannel);
-#endif
-        }
-        else if (enmDir == PDMAUDIODIR_IN)
-        {
-            pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_LINE_IN,    uSD, uChannel);
-#ifdef VBOX_WITH_HDA_MIC_IN
-            pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_MIC_IN,     uSD, uChannel);
-#endif
-        }
-    }
-
-    if (pu32Addr)
-        hdaCodecSetRegisterU8(pu32Addr, cmd, 0);
-
+        AssertFailedReturn(VINF_SUCCESS);
+    hdaCodecSetRegisterU8(pu32addr, cmd, 0);
     return VINF_SUCCESS;
 }
 
-/* A0 */
 static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param;
     else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
@@ -2392,19 +2069,19 @@ static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param;
     else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param;
-    else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
-        *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32A_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
-/* Also see section 3.7.1. */
 static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
         hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
     else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
@@ -2413,35 +2090,42 @@ static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd
         hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
     else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
         hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
-    else
-        LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
 /* F0C */
 static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
     else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
 /* 70C */
 static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
-    *pResp = 0;
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
 
-    uint32_t *pu32Reg = NULL;
+    *pResp = 0;
+    uint32_t *pu32Reg;
     if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
     else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
@@ -2449,10 +2133,8 @@ static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
     else
-        LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    if (pu32Reg)
-        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
+        AssertFailedReturn(VINF_SUCCESS);
+    hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
 
     return VINF_SUCCESS;
 }
@@ -2460,101 +2142,87 @@ static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd
 /* F0F */
 static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
 /* 70F */
 static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
-    *pResp = 0;
-
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     uint32_t *pu32Reg = NULL;
+    *pResp = 0;
     if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+    Assert(pu32Reg);
     if (pu32Reg)
         hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
-    return VINF_SUCCESS;
-}
-
-/* F15 */
-static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    RT_NOREF(pThis, cmd);
-    *pResp = 0;
-    return VINF_SUCCESS;
-}
-
-/* 715 */
-static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    RT_NOREF(pThis, cmd);
-    *pResp = 0;
-    return VINF_SUCCESS;
-}
-
-/* F16 */
-static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    RT_NOREF(pThis, cmd);
-    *pResp = 0;
-    return VINF_SUCCESS;
-}
-
-/* 716 */
-static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    RT_NOREF(pThis, cmd);
-    *pResp = 0;
     return VINF_SUCCESS;
 }
 
 /* F17 */
 static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
-    /* Note: this is true for ALC885. */
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    /* note: this is true for ALC885 */
+    if (CODEC_NID(cmd) == 0x1 /* AFG */)
         *pResp = pThis->paNodes[1].afg.u32F17_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get GPIO unsolisted command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
 /* 717 */
 static DECLCALLBACK(int) vrbProcSetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
-    *pResp = 0;
-
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     uint32_t *pu32Reg = NULL;
-    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    *pResp = 0;
+    if (CODEC_NID(cmd) == 1 /* AFG */)
         pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled set GPIO unsolisted command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+    Assert(pu32Reg);
     if (pu32Reg)
         hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
     return VINF_SUCCESS;
 }
 
 /* F1C */
 static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     *pResp = 0;
-
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
     else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -2567,14 +2235,18 @@ static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_
         *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
     else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
     return VINF_SUCCESS;
 }
 
 static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
 {
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+    if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+    {
+        LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
     uint32_t *pu32Reg = NULL;
     if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
@@ -2588,12 +2260,9 @@ static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
     else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
-
+    Assert(pu32Reg);
     if (pu32Reg)
         hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
-
     return VINF_SUCCESS;
 }
 
@@ -2625,35 +2294,6 @@ static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64
     return codecSetConfigX(pThis, cmd, 24);
 }
 
-/* F04 */
-static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    *pResp = 0;
-
-    if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
-        *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    return VINF_SUCCESS;
-}
-
-/* 704 */
-static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
-    *pResp = 0;
-
-    uint32_t *pu32Reg = NULL;
-    if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
-        pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
-    else
-        LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
-    if (pu32Reg)
-        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
-    return VINF_SUCCESS;
-}
 
 /**
  * HDA codec verb map.
@@ -2661,59 +2301,52 @@ static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint
  */
 static const CODECVERB g_aCodecVerbs[] =
 {
-    /* Verb        Verb mask            Callback                        Name
-     * ---------- --------------------- ----------------------------------------------------------
-     */
-    { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter           , "GetParameter          " },
-    { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl       , "GetConSelectCtrl      " },
-    { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl       , "SetConSelectCtrl      " },
-    { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId            , "GetStreamId           " },
-    { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId            , "SetStreamId           " },
-    { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl             , "GetPinCtrl            " },
-    { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl             , "SetPinCtrl            " },
-    { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled  , "GetUnsolicitedEnabled " },
-    { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled  , "SetUnsolicitedEnabled " },
-    { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense            , "GetPinSense           " },
-    { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense            , "SetPinSense           " },
-    { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
-    { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState     , "GetProcessingState    " },
-    { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState     , "SetProcessingState    " },
-    { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter    , "GetDigitalConverter   " },
-    { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1   , "SetDigitalConverter1  " },
-    { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2   , "SetDigitalConverter2  " },
-    { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId               , "GetSubId              " },
-    { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0              , "SetSubId0             " },
-    { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1              , "SetSubId1             " },
-    { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2              , "SetSubId2             " },
-    { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3              , "SetSubId3             " },
-    { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset                  , "Reset                 " },
-    { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState          , "GetPowerState         " },
-    { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState          , "SetPowerState         " },
-    { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled     , "GetEAPD_BTLEnabled    " },
-    { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled     , "SetEAPD_BTLEnabled    " },
-    { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl      , "GetVolumeKnobCtrl     " },
-    { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl      , "SetVolumeKnobCtrl     " },
-    { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData            , "GetGPIOData           " },
-    { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData            , "SetGPIOData           " },
-    { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask      , "GetGPIOEnableMask     " },
-    { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask      , "SetGPIOEnableMask     " },
-    { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted      , "GetGPIOUnsolisted     " },
-    { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted      , "SetGPIOUnsolisted     " },
-    { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig              , "GetConfig             " },
-    { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0             , "SetConfig0            " },
-    { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1             , "SetConfig1            " },
-    { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2             , "SetConfig2            " },
-    { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3             , "SetConfig3            " },
-    { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat     , "GetConverterFormat    " },
-    { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat     , "SetConverterFormat    " },
-    { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier           , "GetAmplifier          " },
-    { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier           , "SetAmplifier          " },
-    { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect           , "GetSDISelect          " },
-    { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect           , "SetSDISelect          " }
-    /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
+/*     verb     | verb mask              | callback               */
+/*   -----------  --------------------   -----------------------  */
+    { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter           },
+    { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl       },
+    { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl       },
+    { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId            },
+    { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId            },
+    { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl             },
+    { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl             },
+    { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled  },
+    { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled  },
+    { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense            },
+    { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense            },
+    { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry },
+    { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState     },
+    { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState     },
+    { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter    },
+    { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1   },
+    { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2   },
+    { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId               },
+    { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0              },
+    { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1              },
+    { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2              },
+    { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3              },
+    { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset                  },
+    { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState          },
+    { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState          },
+    { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled     },
+    { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled     },
+    { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl      },
+    { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl      },
+    { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted      },
+    { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted      },
+    { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig              },
+    { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0             },
+    { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1             },
+    { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2             },
+    { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3             },
+    { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat     },
+    { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat     },
+    { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier           },
+    { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier           },
 };
 
 #ifdef DEBUG
+
 typedef struct CODECDBGINFO
 {
     /** DBGF info helpers. */
@@ -2766,7 +2399,6 @@ static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
     codecDbgPrintf(pInfo, "Parameters (F00):\n");
 
     CODECDBG_INDENT
-        codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
         codecDbgPrintf(pInfo, "Amplifier Caps:\n");
         uint32_t uReg = paReg00[0xD];
         CODECDBG_INDENT
@@ -2781,7 +2413,7 @@ static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
                            CODEC_F00_12_NUM_STEPS(uReg),
                            CODEC_F00_12_STEP_SIZE(uReg),
                            CODEC_F00_12_OFFSET(uReg),
-                           RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
+                           RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
         CODECDBG_UNINDENT
     CODECDBG_UNINDENT
 }
@@ -2803,7 +2435,7 @@ static void codecDbgPrintNodeAmp(PCODECDBGINFO pInfo, uint32_t *paReg, uint8_t u
 #undef CODECDBG_AMP
 }
 
-#if 0 /* unused */
+#if 0 // unused
 static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
 {
     if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
@@ -2814,15 +2446,15 @@ static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
 }
 #endif
 
-static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecursive)
+static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode)
 {
-    codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
+    codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.id, pNode->node.id);
 
-    if (pNode->node.uID == STAC9220_NID_ROOT)
+    if (pNode->node.id == STAC9220_NID_ROOT)
     {
         CODECDBG_PRINT("ROOT\n");
     }
-    else if (pNode->node.uID == STAC9220_NID_AFG)
+    else if (pNode->node.id == STAC9220_NID_AFG)
     {
         CODECDBG_PRINT("AFG\n");
         CODECDBG_INDENT
@@ -2830,11 +2462,11 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
             codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
         CODECDBG_UNINDENT
     }
-    else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("PORT\n");
     }
-    else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("DAC\n");
         CODECDBG_INDENT
@@ -2844,7 +2476,7 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
             codecDbgPrintNodeAmp   (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
         CODECDBG_UNINDENT
     }
-    else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("ADC VOLUME\n");
         CODECDBG_INDENT
@@ -2853,7 +2485,7 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
             codecDbgPrintNodeAmp   (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
         CODECDBG_UNINDENT
     }
-    else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("ADC\n");
         CODECDBG_INDENT
@@ -2863,7 +2495,7 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
             codecDbgPrintNodeAmp   (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
         CODECDBG_UNINDENT
     }
-    else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("ADC MUX\n");
         CODECDBG_INDENT
@@ -2872,78 +2504,46 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
             codecDbgPrintNodeAmp   (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
         CODECDBG_UNINDENT
     }
-    else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("PC BEEP\n");
     }
-    else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("SPDIF OUT\n");
     }
-    else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("SPDIF IN\n");
     }
-    else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("DIGITAL IN PIN\n");
     }
-    else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("DIGITAL OUT PIN\n");
     }
-    else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("CD\n");
     }
-    else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("VOLUME KNOB\n");
     }
-    else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
+    else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.id))
     {
         CODECDBG_PRINT("RESERVED\n");
     }
     else
-        CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
-
-    if (fRecursive)
-    {
-#define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry)                              \
-        if (cCnt >= _aEntry)                                                       \
-        {                                                                          \
-            const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
-            if (pNode->node.uID == uID)                                             \
-                codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */);          \
-        }
-
-        /* Slow recursion, but this is debug stuff anyway. */
-        for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
-        {
-            const PCODECNODE pSubNode = &pInfo->pThis->paNodes[i];
-            if (pSubNode->node.uID == pNode->node.uID)
-                continue;
-
-            const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
-            if (cCnt == 0) /* No connections present? Skip. */
-                continue;
-
-            CODECDBG_INDENT
-                CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
-                CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
-                CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
-                CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
-            CODECDBG_UNINDENT
-        }
-
-#undef CODECDBG_PRINT_CONLIST_ENTRY
-   }
+        CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.id);
 }
 
 static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     RT_NOREF(pszArgs);
-    pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
+    pHlp->pfnPrintf(pHlp, "HDA LINK\n");
 
     CODECDBGINFO dbgInfo;
     dbgInfo.pHlp   = pHlp;
@@ -2956,10 +2556,8 @@ static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp,
         for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
         {
             PCODECNODE pNode = &pThis->paNodes[i];
-
-            /* Start with all nodes which have connection entries set. */
-            if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
-                codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
+            if (pNode->node.au32F00_param[0xE] == 0) /* Start with all nodes connected directly to the HDA (Azalia) link. */
+                codecDbgPrintNode(&dbgInfo, pNode);
         }
     CODECDBG_UNINDENT
 }
@@ -2968,101 +2566,81 @@ static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp,
 {
     RT_NOREF(pThis, pHlp, pszArgs);
 }
-#endif
 
-static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, uint64_t *puResp)
-{
-    AssertPtrReturn(pThis,  VERR_INVALID_POINTER);
-    AssertPtrReturn(puResp, VERR_INVALID_POINTER);
+#endif /* DEBUG */
 
-    if (CODEC_CAD(cmd) != pThis->id)
-    {
-        *puResp = 0;
-        AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
-        return VERR_INVALID_PARAMETER;
-    }
+static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, PPFNHDACODECVERBPROCESSOR pfn)
+{
+    Assert(CODEC_CAD(cmd) == pThis->id);
+    if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
+        LogFlowFunc(("cmd %x was addressed to reserved node\n", cmd));
 
     if (   CODEC_VERBDATA(cmd) == 0
         || CODEC_NID(cmd) >= pThis->cTotalNodes)
     {
-        *puResp = 0;
-        AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
-        return VERR_INVALID_PARAMETER;
+        *pfn = vrbProcUnimplemented;
+        /// @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp)
+        LogFlowFunc(("cmd %x was ignored\n", cmd));
+        return VINF_SUCCESS;
     }
 
-    /** @todo r=andy Implement a binary search here. */
-    for (size_t i = 0; i < pThis->cVerbs; i++)
+    for (int i = 0; i < pThis->cVerbs; ++i)
     {
         if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
         {
-            int rc2 = pThis->paVerbs[i].pfn(pThis, cmd, puResp);
-            AssertRC(rc2);
-            Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
-                      CODEC_NID(cmd), pThis->paVerbs[i].verb, pThis->paVerbs[i].pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
-            return rc2;
+            *pfn = pThis->paVerbs[i].pfn;
+            return VINF_SUCCESS;
         }
     }
 
-    *puResp = 0;
-    LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
-    return VERR_NOT_FOUND;
+    *pfn = vrbProcUnimplemented;
+    LogFlowFunc(("callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
+    return VINF_SUCCESS;
 }
 
 /*
  * APIs exposed to DevHDA.
  */
 
-int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
+/**
+ *
+ * routines open one of the voices (IN, OUT) with corresponding parameters.
+ * this routine could be called from HDA on setting/resseting sound format.
+ *
+ * @todo Probably passed settings should be verified (if AFG's declared proposed
+ *       format) before enabling.
+ */
+int hdaCodecOpenStream(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, PPDMAUDIOSTREAMCFG pCfg)
 {
     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
 
-    int rc = VINF_SUCCESS;
-
-    switch (enmMixerCtl)
+    int rc;
+    switch (enmSoundSource)
     {
-        case PDMAUDIOMIXERCTL_VOLUME_MASTER:
-        case PDMAUDIOMIXERCTL_FRONT:
-#ifdef VBOX_WITH_HDA_51_SURROUND
-        case PDMAUDIOMIXERCTL_CENTER_LFE:
-        case PDMAUDIOMIXERCTL_REAR:
-#endif
-        {
+        case PI_INDEX:
+            rc = pThis->pfnOpenIn(pThis->pHDAState,  "hda.in", PDMAUDIORECSOURCE_LINE_IN, pCfg);
             break;
-        }
-        case PDMAUDIOMIXERCTL_LINE_IN:
 #ifdef VBOX_WITH_HDA_MIC_IN
-        case PDMAUDIOMIXERCTL_MIC_IN:
+        case MC_INDEX:
+            rc = pThis->pfnOpenIn(pThis->pHDAState,  "hda.mc", PDMAUDIORECSOURCE_MIC, pCfg);
+            break;
 #endif
-        {
+        case PO_INDEX:
+            rc = pThis->pfnOpenOut(pThis->pHDAState, "hda.out", pCfg);
             break;
-        }
+
         default:
-            AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
+            AssertMsgFailed(("Index %ld not implemented\n", enmSoundSource));
             rc = VERR_NOT_IMPLEMENTED;
-            break;
     }
 
-    if (RT_SUCCESS(rc))
-        rc = pThis->pfnMixerAddStream(pThis->pHDAState, enmMixerCtl, pCfg);
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    int rc = pThis->pfnMixerRemoveStream(pThis->pHDAState, enmMixerCtl);
-
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
 int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
 {
-    AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
+    AssertLogRelMsgReturn(pThis->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
                           VERR_INTERNAL_ERROR);
     SSMR3PutU32(pSSM, pThis->cTotalNodes);
     for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
@@ -3113,14 +2691,14 @@ int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
 
     for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
     {
-        uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.uID;
+        uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.id;
         int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState,
                                   sizeof(pThis->paNodes[idxNode].SavedState),
                                   fFlags, pFields, NULL);
         if (RT_FAILURE(rc))
             return rc;
-        AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.uID,
-                              ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.uID, idOld),
+        AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.id,
+                              ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.id, idOld),
                               VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
     }
 
@@ -3128,171 +2706,78 @@ int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
      * Update stuff after changing the state.
      */
     if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
-        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_FRONT);
+        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
     else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
-        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
+        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_PCM);
     hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
 
     return VINF_SUCCESS;
 }
 
-/**
- * Powers off the codec.
- *
- * @param   pThis           Codec to power off.
- */
-void hdaCodecPowerOff(PHDACODEC pThis)
+int hdaCodecDestruct(PHDACODEC pThis)
 {
-    if (!pThis)
-        return;
-
-    LogFlowFuncEnter();
-
-    LogRel2(("HDA: Powering off codec ...\n"));
-
-    int rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_FRONT);
-    AssertRC(rc2);
-#ifdef VBOX_WITH_HDA_51_SURROUND
-    rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE);
-    AssertRC(rc2);
-    rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_REAR);
-    AssertRC(rc2);
-#endif
-
-#ifdef VBOX_WITH_HDA_MIC_IN
-    rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_MIC_IN);
-    AssertRC(rc2);
-#endif
-    rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_LINE_IN);
-    AssertRC(rc2);
-}
-
-void hdaCodecDestruct(PHDACODEC pThis)
-{
-    if (!pThis)
-        return;
-
-    LogFlowFuncEnter();
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
 
     if (pThis->paNodes)
     {
         RTMemFree(pThis->paNodes);
         pThis->paNodes = NULL;
     }
+
+    return VINF_SUCCESS;
 }
 
 int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
                       uint16_t uLUN, PCFGMNODE pCfg)
 {
     AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
 
-    pThis->id      = uLUN;
-    pThis->paVerbs = &g_aCodecVerbs[0];
-    pThis->cVerbs  = RT_ELEMENTS(g_aCodecVerbs);
+    pThis->id        = uLUN;
+    pThis->paVerbs   = &g_aCodecVerbs[0];
+    pThis->cVerbs    = RT_ELEMENTS(g_aCodecVerbs);
 
+    pThis->pfnLookup       = codecLookup;
 #ifdef DEBUG
     pThis->pfnDbgSelector  = codecDbgSelector;
     pThis->pfnDbgListNodes = codecDbgListNodes;
 #endif
-    pThis->pfnLookup       = codecLookup;
-
     int rc = stac9220Construct(pThis);
-    AssertRCReturn(rc, rc);
-
-    /* Common root node initializers. */
-    pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
-    pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
-
-    /* Common AFG node initializers. */
-    pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
-    pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
-    pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
-    pThis->paNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
-
-    do
-    {
-        /* Initialize the streams to some default values (44.1 kHz, 16-bit signed, 2 channels).
-         * The codec's (fixed) delivery rate is 48kHz, so a frame will be delivered every 20.83us. */
-        PDMAUDIOSTREAMCFG strmCfg;
-        RT_ZERO(strmCfg);
-        strmCfg.uHz           = 44100;
-        strmCfg.cChannels     = 2;
-        strmCfg.enmFormat     = PDMAUDIOFMT_S16;
-        strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
-        /* Note: Adding the default input/output streams is *not* critical for the overall
-         *       codec construction result. */
-
-        /*
-         * Output streams.
-         */
-        strmCfg.enmDir = PDMAUDIODIR_OUT;
-
-        /* Front. */
-        RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Front");
-        strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
-        int rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_FRONT, &strmCfg);
-        if (RT_FAILURE(rc2))
-            LogRel2(("HDA: Failed to add front output stream: %Rrc\n", rc2));
-
-#ifdef VBOX_WITH_HDA_51_SURROUND
-        /* Center / LFE. */
-        RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Center / LFE");
-        strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
-        /** @todo Handle mono channel if only center *or* LFE is available? */
-        rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, &strmCfg);
-        if (RT_FAILURE(rc2))
-            LogRel2(("HDA: Failed to add center/LFE output stream: %Rrc\n", rc2));
-
-        /* Rear. */
-        RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Rear");
-        strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
-        rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_REAR, &strmCfg);
-        if (RT_FAILURE(rc2))
-            LogRel2(("HDA: Failed to add rear output stream: %Rrc\n", rc2));
-#endif
-
-        /*
-         * Input streams.
-         */
-        strmCfg.enmDir = PDMAUDIODIR_IN;
-
+    AssertRC(rc);
+
+    /* common root node initializers */
+    pThis->paNodes[0].node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
+    pThis->paNodes[0].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
+    /* common AFG node initializers */
+    pThis->paNodes[1].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
+    pThis->paNodes[1].node.au32F00_param[5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
+    pThis->paNodes[1].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
+
+    /* This codec uses a fixed setting (44.1 kHz, 16-bit signed, 2 channels). */
+    pThis->strmCfg.uHz           = 44100;
+    pThis->strmCfg.cChannels     = 2;
+    pThis->strmCfg.enmFormat     = AUD_FMT_S16;
+    pThis->strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+    hdaCodecOpenStream(pThis, PI_INDEX, &pThis->strmCfg);
 #ifdef VBOX_WITH_HDA_MIC_IN
-        RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Microphone In");
-        strmCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
-        rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_MIC_IN, &strmCfg);
-        if (RT_FAILURE(rc2))
-            LogRel2(("HDA: Failed to add microphone input stream: %Rrc\n", rc2));
+    hdaCodecOpenStream(pThis, MC_INDEX, &pThis->strmCfg);
 #endif
-        RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Line In");
-        strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
-        rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_LINE_IN, &strmCfg);
-        if (RT_FAILURE(rc2))
-            LogRel2(("HDA: Failed to add line input stream: %Rrc\n", rc2));
+    hdaCodecOpenStream(pThis, PO_INDEX, &pThis->strmCfg);
 
-    } while (0);
+    /* Initialize the AFG node with the fixed setting. */
+    pThis->paNodes[1].node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
 
-    /*
-     * Reset nodes.
-     */
     AssertPtr(pThis->paNodes);
     AssertPtr(pThis->pfnCodecNodeReset);
 
     for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
         pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
 
-    /*
-     * Set initial volume.
-     */
-    hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params,       PDMAUDIOMIXERCTL_FRONT);
+    hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params,       PDMAUDIOMIXERCTL_PCM);
     hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
-#ifdef VBOX_WITH_HDA_MIC_IN
-    #error "Implement mic-in support!"
-#endif
 
-    LogFlowFuncLeaveRC(rc);
-    return rc;
+    return VINF_SUCCESS;
 }
 
diff --git a/src/VBox/Devices/Audio_50/Makefile.kup b/src/VBox/Devices/Audio_50/Makefile.kup
new file mode 100644
index 0000000..e69de29
diff --git a/src/VBox/Devices/Audio_50/alsa_mangling.h b/src/VBox/Devices/Audio_50/alsa_mangling.h
new file mode 100644
index 0000000..fde5840
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/alsa_mangling.h
@@ -0,0 +1,55 @@
+/** @file
+ *
+ * Mangle libasound symbols. This is necessary on hosts which don't
+ * support the -fvisibility gcc switch.
+ */
+
+/*
+ * Copyright (C) 2013-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef AUDIO_ALSA_MANGLING_H
+#define AUDIO_ALSA_MANGLING_H
+
+#define ALSA_MANGLER(symbol) VBox_##symbol
+
+#define snd_pcm_hw_params_any                   ALSA_MANGLER(snd_pcm_hw_params_any)
+#define snd_pcm_close                           ALSA_MANGLER(snd_pcm_close)
+#define snd_pcm_avail_update                    ALSA_MANGLER(snd_pcm_avail_update)
+#define snd_pcm_hw_params_set_channels_near     ALSA_MANGLER(snd_pcm_hw_params_set_channels_near)
+#define snd_pcm_hw_params_set_period_time_near  ALSA_MANGLER(snd_pcm_hw_params_set_period_time_near)
+#define snd_pcm_prepare                         ALSA_MANGLER(snd_pcm_prepare)
+#define snd_pcm_sw_params_sizeof                ALSA_MANGLER(snd_pcm_sw_params_sizeof)
+#define snd_pcm_hw_params_set_period_size_near  ALSA_MANGLER(snd_pcm_hw_params_set_period_size_near)
+#define snd_pcm_hw_params_get_period_size       ALSA_MANGLER(snd_pcm_hw_params_get_period_size)
+#define snd_pcm_hw_params                       ALSA_MANGLER(snd_pcm_hw_params)
+#define snd_pcm_hw_params_sizeof                ALSA_MANGLER(snd_pcm_hw_params_sizeof)
+#define snd_pcm_state                           ALSA_MANGLER(snd_pcm_state)
+#define snd_pcm_open                            ALSA_MANGLER(snd_pcm_open)
+#define snd_lib_error_set_handler               ALSA_MANGLER(snd_lib_error_set_handler)
+#define snd_pcm_sw_params                       ALSA_MANGLER(snd_pcm_sw_params)
+#define snd_pcm_hw_params_get_period_size_min   ALSA_MANGLER(snd_pcm_hw_params_get_period_size_min)
+#define snd_pcm_writei                          ALSA_MANGLER(snd_pcm_writei)
+#define snd_pcm_readi                           ALSA_MANGLER(snd_pcm_readi)
+#define snd_strerror                            ALSA_MANGLER(snd_strerror)
+#define snd_pcm_drop                            ALSA_MANGLER(snd_pcm_drop)
+#define snd_pcm_resume                          ALSA_MANGLER(snd_pcm_resume)
+#define snd_pcm_hw_params_get_buffer_size       ALSA_MANGLER(snd_pcm_hw_params_get_buffer_size)
+#define snd_pcm_hw_params_set_rate_near         ALSA_MANGLER(snd_pcm_hw_params_set_rate_near)
+#define snd_pcm_hw_params_set_access            ALSA_MANGLER(snd_pcm_hw_params_set_access)
+#define snd_pcm_hw_params_set_buffer_time_near  ALSA_MANGLER(snd_pcm_hw_params_set_buffer_time_near)
+#define snd_pcm_hw_params_set_buffer_size_near  ALSA_MANGLER(snd_pcm_hw_params_set_buffer_size_near)
+#define snd_pcm_hw_params_get_buffer_size_min   ALSA_MANGLER(snd_pcm_hw_params_get_buffer_size_min)
+#define snd_pcm_hw_params_set_format            ALSA_MANGLER(snd_pcm_hw_params_set_format)
+#define snd_pcm_sw_params_current               ALSA_MANGLER(snd_pcm_sw_params_current)
+#define snd_pcm_sw_params_set_start_threshold   ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold)
+
+#endif /* !AUDIO_ALSA_MANGLING_H */
diff --git a/src/VBox/Devices/Audio/alsa_stubs.c b/src/VBox/Devices/Audio_50/alsa_stubs.c
similarity index 91%
copy from src/VBox/Devices/Audio/alsa_stubs.c
copy to src/VBox/Devices/Audio_50/alsa_stubs.c
index fbed735..cda485b 100644
--- a/src/VBox/Devices/Audio/alsa_stubs.c
+++ b/src/VBox/Devices/Audio_50/alsa_stubs.c
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
  * available from http://www.virtualbox.org. This file is free software;
@@ -35,16 +35,6 @@
         return pfn_ ## function shortsig; \
     }
 
-PROXY_STUB(snd_device_name_hint, int,
-           (int card, const char *iface, void ***hints),
-           (card, iface, hints))
-PROXY_STUB(snd_device_name_free_hint, int,
-           (void ***hints),
-           (hints))
-PROXY_STUB(snd_device_name_get_hint, char *,
-           (const void *hint, const char *id),
-           (hint, id))
-
 PROXY_STUB(snd_pcm_hw_params_any, int,
            (snd_pcm_t *pcm, snd_pcm_hw_params_t *params),
            (pcm, params))
@@ -117,9 +107,6 @@ PROXY_STUB(snd_pcm_sw_params_current, int,
 PROXY_STUB(snd_pcm_sw_params_set_start_threshold, int,
            (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
            (pcm, params, val))
-PROXY_STUB(snd_pcm_sw_params_set_avail_min, int,
-           (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
-           (pcm, params, val))
 
 typedef struct
 {
@@ -130,10 +117,6 @@ typedef struct
 #define ELEMENT(function) { #function , (void (**)(void)) & pfn_ ## function }
 static SHARED_FUNC SharedFuncs[] =
 {
-    ELEMENT(snd_device_name_hint),
-    ELEMENT(snd_device_name_get_hint),
-    ELEMENT(snd_device_name_free_hint),
-
     ELEMENT(snd_pcm_hw_params_any),
     ELEMENT(snd_pcm_close),
     ELEMENT(snd_pcm_avail_update),
@@ -164,7 +147,6 @@ static SHARED_FUNC SharedFuncs[] =
     ELEMENT(snd_pcm_hw_params_set_format),
     ELEMENT(snd_pcm_sw_params_current),
     ELEMENT(snd_pcm_sw_params_set_start_threshold),
-    ELEMENT(snd_pcm_sw_params_set_avail_min)
 };
 #undef ELEMENT
 
diff --git a/src/VBox/Devices/Audio_50/alsa_stubs.h b/src/VBox/Devices/Audio_50/alsa_stubs.h
new file mode 100644
index 0000000..889add3
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/alsa_stubs.h
@@ -0,0 +1,21 @@
+/** @file
+ *
+ * Stubs for libasound.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef AUDIO_ALSA_STUBS_H
+# define AUDIO_ALSA_STUBS_H
+extern int audioLoadAlsaLib(void);
+#endif
diff --git a/src/VBox/Devices/Audio_50/pulse_mangling.h b/src/VBox/Devices/Audio_50/pulse_mangling.h
new file mode 100644
index 0000000..8b02ef3
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/pulse_mangling.h
@@ -0,0 +1,69 @@
+/** @file
+ *
+ * Mangle libpulse symbols. This is necessary on hosts which don't
+ * support the -fvisibility gcc switch.
+ */
+
+/*
+ * Copyright (C) 2013-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef AUDIO_PULSE_MANGLING_H
+#define AUDIO_PULSE_MANGLING_H
+
+#define PULSE_MANGLER(symbol) VBox_##symbol
+
+#define pa_stream_connect_playback              PULSE_MANGLER(pa_stream_connect_playback)
+#define pa_stream_connect_record                PULSE_MANGLER(pa_stream_connect_record)
+#define pa_stream_disconnect                    PULSE_MANGLER(pa_stream_disconnect)
+#define pa_stream_get_sample_spec               PULSE_MANGLER(pa_stream_get_sample_spec)
+#define pa_stream_set_latency_update_callback   PULSE_MANGLER(pa_stream_set_latency_update_callback)
+#define pa_stream_write                         PULSE_MANGLER(pa_stream_write)
+#define pa_stream_unref                         PULSE_MANGLER(pa_stream_unref)
+#define pa_stream_get_state                     PULSE_MANGLER(pa_stream_get_state)
+#define pa_stream_set_state_callback            PULSE_MANGLER(pa_stream_set_state_callback)
+#define pa_stream_flush                         PULSE_MANGLER(pa_stream_flush)
+#define pa_stream_drain                         PULSE_MANGLER(pa_stream_drain)
+#define pa_stream_trigger                       PULSE_MANGLER(pa_stream_trigger)
+#define pa_stream_new                           PULSE_MANGLER(pa_stream_new)
+#define pa_stream_get_buffer_attr               PULSE_MANGLER(pa_stream_get_buffer_attr)
+#define pa_stream_peek                          PULSE_MANGLER(pa_stream_peek)
+#define pa_stream_cork                          PULSE_MANGLER(pa_stream_cork)
+#define pa_stream_drop                          PULSE_MANGLER(pa_stream_drop)
+#define pa_stream_writable_size                 PULSE_MANGLER(pa_stream_writable_size)
+#define pa_context_connect                      PULSE_MANGLER(pa_context_connect)
+#define pa_context_disconnect                   PULSE_MANGLER(pa_context_disconnect)
+#define pa_context_get_state                    PULSE_MANGLER(pa_context_get_state)
+#define pa_context_unref                        PULSE_MANGLER(pa_context_unref)
+#define pa_context_errno                        PULSE_MANGLER(pa_context_errno)
+#define pa_context_new                          PULSE_MANGLER(pa_context_new)
+#define pa_context_set_state_callback           PULSE_MANGLER(pa_context_set_state_callback)
+#define pa_threaded_mainloop_stop               PULSE_MANGLER(pa_threaded_mainloop_stop)
+#define pa_threaded_mainloop_get_api            PULSE_MANGLER(pa_threaded_mainloop_get_api)
+#define pa_threaded_mainloop_free               PULSE_MANGLER(pa_threaded_mainloop_free)
+#define pa_threaded_mainloop_signal             PULSE_MANGLER(pa_threaded_mainloop_signal)
+#define pa_threaded_mainloop_unlock             PULSE_MANGLER(pa_threaded_mainloop_unlock)
+#define pa_threaded_mainloop_new                PULSE_MANGLER(pa_threaded_mainloop_new)
+#define pa_threaded_mainloop_wait               PULSE_MANGLER(pa_threaded_mainloop_wait)
+#define pa_threaded_mainloop_start              PULSE_MANGLER(pa_threaded_mainloop_start)
+#define pa_threaded_mainloop_lock               PULSE_MANGLER(pa_threaded_mainloop_lock)
+#define pa_bytes_per_second                     PULSE_MANGLER(pa_bytes_per_second)
+#define pa_frame_size                           PULSE_MANGLER(pa_frame_size)
+#define pa_sample_format_to_string              PULSE_MANGLER(pa_sample_format_to_string)
+#define pa_sample_spec_valid                    PULSE_MANGLER(pa_sample_spec_valid)
+#define pa_channel_map_init_auto                PULSE_MANGLER(pa_channel_map_init_auto)
+#define pa_operation_unref                      PULSE_MANGLER(pa_operation_unref)
+#define pa_operation_get_state                  PULSE_MANGLER(pa_operation_get_state)
+#define pa_operation_cancel                     PULSE_MANGLER(pa_operation_cancel)
+#define pa_strerror                             PULSE_MANGLER(pa_strerror)
+#define pa_stream_readable_size                 PULSE_MANGLER(pa_stream_readable_size)
+
+#endif /* !AUDIO_PULSE_MANGLING_H */
diff --git a/src/VBox/Devices/Audio/pulse_stubs.c b/src/VBox/Devices/Audio_50/pulse_stubs.c
similarity index 92%
copy from src/VBox/Devices/Audio/pulse_stubs.c
copy to src/VBox/Devices/Audio_50/pulse_stubs.c
index 7464ee2..c38c090 100644
--- a/src/VBox/Devices/Audio/pulse_stubs.c
+++ b/src/VBox/Devices/Audio_50/pulse_stubs.c
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
  * available from http://www.virtualbox.org. This file is free software;
@@ -110,20 +110,12 @@ PROXY_STUB     (pa_stream_writable_size, size_t,
                 (pa_stream *p),
                 (p))
 PROXY_STUB     (pa_context_connect, int,
-                (pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api),
+                (pa_context *c, const char *server, pa_context_flags_t flags,
+                 const pa_spawn_api *api),
                 (c, server, flags, api))
 PROXY_STUB_VOID(pa_context_disconnect,
                 (pa_context *c),
                 (c))
-PROXY_STUB     (pa_context_get_server_info, pa_operation*,
-                (pa_context *c, const char *name, pa_server_info_cb_t cb, void *userdata),
-                (c, name, cb, userdata))
-PROXY_STUB     (pa_context_get_sink_info_by_name, pa_operation*,
-                (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata),
-                (c, name, cb, userdata))
-PROXY_STUB     (pa_context_get_source_info_by_name, pa_operation*,
-                (pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata),
-                (c, name, cb, userdata))
 PROXY_STUB     (pa_context_get_state, pa_context_state_t,
                 (pa_context *c),
                 (c))
@@ -227,9 +219,6 @@ static SHARED_FUNC SharedFuncs[] =
     ELEMENT(pa_stream_writable_size),
     ELEMENT(pa_context_connect),
     ELEMENT(pa_context_disconnect),
-    ELEMENT(pa_context_get_server_info),
-    ELEMENT(pa_context_get_sink_info_by_name),
-    ELEMENT(pa_context_get_source_info_by_name),
     ELEMENT(pa_context_get_state),
     ELEMENT(pa_context_unref),
     ELEMENT(pa_context_errno),
@@ -295,3 +284,4 @@ int audioLoadPulseLib(void)
     isLibLoaded = YES;
     return rc;
 }
+
diff --git a/src/VBox/Devices/Audio_50/pulse_stubs.h b/src/VBox/Devices/Audio_50/pulse_stubs.h
new file mode 100644
index 0000000..af393d3
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/pulse_stubs.h
@@ -0,0 +1,21 @@
+/** @file
+ *
+ * Stubs for libpulse.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef AUDIO_PULSE_STUBS_H
+#define AUDIO_PULSE_STUBS_H
+extern int audioLoadPulseLib(void);
+#endif
diff --git a/src/VBox/Devices/Audio_50/sys-queue.h b/src/VBox/Devices/Audio_50/sys-queue.h
new file mode 100644
index 0000000..5b6e2a0
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/sys-queue.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.3 (Berkeley) 12/13/93
+ */
+
+#ifndef	_SYS_QUEUE_H
+#define	_SYS_QUEUE_H 1
+
+/*
+ * This file defines three types of data structures: lists, tail queues,
+ * and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list after
+ * an existing element or at the head of the list. A list may only be
+ * traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A tail queue may only be traversed in the forward direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+#define	LIST_INIT(head) {						\
+	(head)->lh_first = NULL;					\
+}
+
+#define LIST_INSERT_AFTER(listelm, elm, field) {			\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+}
+
+#define LIST_INSERT_HEAD(head, elm, field) {				\
+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+}
+
+#define LIST_REMOVE(elm, field) {					\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev = 			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+}
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_INIT(head) {						\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+}
+
+#define TAILQ_INSERT_HEAD(head, elm, field) {				\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+}
+
+#define TAILQ_INSERT_TAIL(head, elm, field) {				\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+}
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) {			\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+}
+
+#define TAILQ_REMOVE(head, elm, field) {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+}
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_INIT(head) {						\
+	(head)->cqh_first = (void *)(head);				\
+	(head)->cqh_last = (void *)(head);				\
+}
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) {		\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == (void *)(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+}
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) {		\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == (void *)(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+}
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) {				\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = (void *)(head);				\
+	if ((head)->cqh_last == (void *)(head))				\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+}
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) {				\
+	(elm)->field.cqe_next = (void *)(head);				\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == (void *)(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+}
+
+#define	CIRCLEQ_REMOVE(head, elm, field) {				\
+	if ((elm)->field.cqe_next == (void *)(head))			\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == (void *)(head))			\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+}
+#endif	/* sys/queue.h */
diff --git a/src/VBox/Devices/Audio_50/testcase/Makefile.kmk b/src/VBox/Devices/Audio_50/testcase/Makefile.kmk
new file mode 100644
index 0000000..8a0d8fe
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/testcase/Makefile.kmk
@@ -0,0 +1,41 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the audio testcases.
+#
+
+#
+# Copyright (C) 2014-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK)
+
+ PROGRAMS += tstAudioMixBuffer
+ TESTING  += $(tstAudioMixBuffer_0_OUTDIR)/tstAudioMixBuffer.run
+
+ tstAudioMixBuffer_TEMPLATE = VBOXR3TSTEXE
+ tstAudioMixBuffer_DEFS    += TESTCASE $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
+ tstAudioMixBuffer_SOURCES  = \
+	tstAudioMixBuffer.cpp \
+	../AudioMixBuffer.cpp \
+	../DrvAudioCommon.cpp
+ tstAudioMixBuffer_LIBS     = $(LIB_RUNTIME)
+
+ $$(tstAudioMixBuffer_0_OUTDIR)/tstAudioMixBuffer.run: $$(tstAudioMixBuffer_1_STAGE_TARGET)
+	export VBOX_LOG_DEST=nofile; $(tstAudioMixBuffer_1_STAGE_TARGET) quiet
+	$(QUIET)$(APPEND) -t "$@" "done"
+
+endif
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/Devices/Audio_50/testcase/tstAudioMixBuffer.cpp b/src/VBox/Devices/Audio_50/testcase/tstAudioMixBuffer.cpp
new file mode 100644
index 0000000..8a99672
--- /dev/null
+++ b/src/VBox/Devices/Audio_50/testcase/tstAudioMixBuffer.cpp
@@ -0,0 +1,592 @@
+/* $Id: tstAudioMixBuffer.cpp $ */
+/** @file
+ * Audio testcase - Mixing buffer.
+ */
+
+/*
+ * Copyright (C) 2014-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/rand.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+#include "../AudioMixBuffer.h"
+#include "../DrvAudio.h"
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+static int tstSingle(RTTEST hTest)
+{
+    RTTestSubF(hTest, "Single buffer");
+
+    PDMAUDIOSTREAMCFG config =
+    {
+        44100,                   /* Hz */
+        2                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+    PDMPCMPROPS props;
+
+    int rc = DrvAudioStreamCfgToProps(&config, &props);
+    AssertRC(rc);
+
+    uint32_t cBufSize = _1K;
+
+    /*
+     * General stuff.
+     */
+    PDMAUDIOMIXBUF mb;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&mb, "Single", &props, cBufSize));
+    RTTESTI_CHECK(AudioMixBufSize(&mb) == cBufSize);
+    RTTESTI_CHECK(AUDIOMIXBUF_B2S(&mb, AudioMixBufSizeBytes(&mb)) == cBufSize);
+    RTTESTI_CHECK(AUDIOMIXBUF_S2B(&mb, AudioMixBufSize(&mb)) == AudioMixBufSizeBytes(&mb));
+    RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize);
+    RTTESTI_CHECK(AUDIOMIXBUF_S2B(&mb, AudioMixBufFree(&mb)) == AudioMixBufFreeBytes(&mb));
+
+    /*
+     * Absolute writes.
+     */
+    uint32_t read  = 0, written = 0, written_abs = 0;
+    int8_t  samples8 [2] = { 0x12, 0x34 };
+    int16_t samples16[2] = { 0xAA, 0xBB };
+    int32_t samples32[2] = { 0xCC, 0xDD };
+    //int64_t samples64[2] = { 0xEE, 0xFF };
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples8, sizeof(samples8), &written));
+    RTTESTI_CHECK(written == 0 /* Samples */);
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples16, sizeof(samples16), &written));
+    RTTESTI_CHECK(written == 1 /* Samples */);
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 2, &samples32, sizeof(samples32), &written));
+    RTTESTI_CHECK(written == 2 /* Samples */);
+    written_abs = 0;
+
+    /* Beyond buffer. */
+    RTTESTI_CHECK_RC(AudioMixBufWriteAt(&mb, AudioMixBufSize(&mb) + 1, &samples16, sizeof(samples16),
+                                        &written), VERR_BUFFER_OVERFLOW);
+
+    /*
+     * Circular writes.
+     */
+    uint32_t cToWrite = AudioMixBufSize(&mb) - written_abs - 1; /* -1 as padding plus -2 samples for above. */
+    for (uint32_t i = 0; i < cToWrite; i++)
+    {
+        RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
+        RTTESTI_CHECK(written == 1);
+    }
+    RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
+    RTTESTI_CHECK(AudioMixBufFree(&mb) == 1);
+    RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, 1U));
+    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cToWrite + written_abs /* + last absolute write */);
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
+    RTTESTI_CHECK(written == 1);
+    RTTESTI_CHECK(AudioMixBufFree(&mb) == 0);
+    RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == (uint32_t)AUDIOMIXBUF_S2B(&mb, 0));
+    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize);
+
+    /* Circular reads. */
+    uint32_t cToRead = AudioMixBufSize(&mb) - written_abs - 1;
+    for (uint32_t i = 0; i < cToWrite; i++)
+    {
+        RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
+        RTTESTI_CHECK(read == 1);
+        AudioMixBufFinish(&mb, read);
+    }
+    RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
+    RTTESTI_CHECK(AudioMixBufFree(&mb) == AudioMixBufSize(&mb) - written_abs - 1);
+    RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs - 1));
+    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize - cToRead + written_abs);
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
+    RTTESTI_CHECK(read == 1);
+    AudioMixBufFinish(&mb, read);
+    RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - written_abs);
+    RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs));
+    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == written_abs);
+
+    AudioMixBufDestroy(&mb);
+
+    return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
+}
+
+static int tstParentChild(RTTEST hTest)
+{
+    RTTestSubF(hTest, "2 Children -> Parent");
+
+    uint32_t cBufSize = _1K;
+
+    PDMAUDIOSTREAMCFG cfg_p =
+    {
+        44100,                   /* Hz */
+        2                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+    PDMPCMPROPS props;
+
+    int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF parent;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
+
+    PDMAUDIOSTREAMCFG cfg_c1 = /* Upmixing to parent */
+    {
+        22100,                   /* Hz */
+        2                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    rc = DrvAudioStreamCfgToProps(&cfg_c1, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF child1;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child1, "Child1", &props, cBufSize));
+    RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child1, &parent));
+
+    PDMAUDIOSTREAMCFG cfg_c2 = /* Downmixing to parent */
+    {
+        48000,                   /* Hz */
+        2                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    rc = DrvAudioStreamCfgToProps(&cfg_c2, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF child2;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child2, "Child2", &props, cBufSize));
+    RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child2, &parent));
+
+    /*
+     * Writing + mixing from child/children -> parent, sequential.
+     */
+    uint32_t cbBuf = _1K;
+    char pvBuf[_1K];
+    int16_t samples[32] = { 0xAA, 0xBB };
+    uint32_t read , written, mixed, temp;
+
+    //unused//uint32_t cChild1Free     = cBufSize;
+    //unused//uint32_t cChild1Mixed    = 0;
+    //unused//uint32_t cSamplesParent1 = 16;
+    uint32_t cSamplesChild1  = 16;
+
+    //unused//uint32_t cChild2Free     = cBufSize;
+    //unused//uint32_t cChild2Mixed    = 0;
+    //unused//uint32_t cSamplesParent2 = 16;
+    uint32_t cSamplesChild2  = 16;
+
+    uint32_t t = RTRandU32() % 64;
+
+    for (uint32_t i = 0; i < t; i++)
+    {
+        RTTestPrintf(hTest, RTTESTLVL_DEBUG, "i=%RU32\n", i);
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child1, 0, &samples, sizeof(samples), &written));
+        RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild1, ("Child1: Expected %RU32 written samples, got %RU32\n", cSamplesChild1, written));
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, written, &mixed));
+        temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child2);
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child1) == temp, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child1), temp));
+
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child2, 0, &samples, sizeof(samples), &written));
+        RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild2, ("Child2: Expected %RU32 written samples, got %RU32\n", cSamplesChild2, written));
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, written, &mixed));
+        temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child1);
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child2) == temp, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child2), temp));
+    }
+
+    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child1) + AudioMixBufMixed(&child2));
+
+    for (;;)
+    {
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, pvBuf, cbBuf, &read));
+        if (!read)
+            break;
+        AudioMixBufFinish(&parent, read);
+    }
+
+    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+    RTTESTI_CHECK(AudioMixBufMixed(&child1) == 0);
+    RTTESTI_CHECK(AudioMixBufMixed(&child2) == 0);
+
+    AudioMixBufDestroy(&parent);
+    AudioMixBufDestroy(&child1);
+    AudioMixBufDestroy(&child2);
+
+    return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
+}
+
+/* Test 8-bit sample conversion (8-bit -> internal -> 8-bit). */
+static int tstConversion8(RTTEST hTest)
+{
+    unsigned        i;
+    uint32_t        cBufSize = 256;
+    PDMPCMPROPS     props;
+
+
+    RTTestSubF(hTest, "Sample conversion");
+
+    PDMAUDIOSTREAMCFG cfg_p =
+    {
+        44100,                   /* Hz */
+        1                        /* Channels */,
+        AUD_FMT_U8               /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF parent;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
+
+    /* Child uses half the sample rate; that ensures the mixing engine can't
+     * take shortcuts and performs conversion. Because conversion to double
+     * the sample rate effectively inserts one additional sample between every
+     * two source samples, N source samples will be converted to N * 2 - 1
+     * samples. However, the last source sample will be saved for later
+     * interpolation and not immediately output.
+     */
+    PDMAUDIOSTREAMCFG cfg_c =   /* Upmixing to parent */
+    {
+        22050,                   /* Hz */
+        1                        /* Channels */,
+        AUD_FMT_U8               /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    rc = DrvAudioStreamCfgToProps(&cfg_c, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF child;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &props, cBufSize));
+    RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
+
+    /* 8-bit unsigned samples. Often used with SB16 device. */
+    uint8_t     samples[16]  = { 0xAA, 0xBB, 0, 1, 43, 125, 126, 127,
+                                 128, 129, 130, 131, 132, UINT8_MAX - 1, UINT8_MAX, 0 };
+
+    /*
+     * Writing + mixing from child -> parent, sequential.
+     */
+    uint32_t    cbBuf = 256;
+    char        achBuf[256];
+    uint32_t    read, written, mixed, temp;
+
+    //unused//uint32_t cChildFree     = cBufSize;
+    //unused//uint32_t cChildMixed    = 0;
+    uint32_t cSamplesChild  = 16;
+    uint32_t cSamplesParent = cSamplesChild * 2 - 2;
+    uint32_t cSamplesRead   = 0;
+
+    /**** 8-bit unsigned samples ****/
+    RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 8-bit\n", cfg_c.uHz, cfg_c.cChannels);
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+    RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+    RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
+    temp = AudioMixBufProcessed(&parent);
+    RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
+
+    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
+
+    for (;;)
+    {
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+        if (!read)
+            break;
+        cSamplesRead += read;
+        AudioMixBufFinish(&parent, read);
+    }
+    RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
+
+    /* Check that the samples came out unharmed. Every other sample is interpolated and we ignore it. */
+    /* NB: This also checks that the default volume setting is 0dB attenuation. */
+    uint8_t *pSrc8 = &samples[0];
+    uint8_t *pDst8 = (uint8_t *)achBuf;
+
+    for (i = 0; i < cSamplesChild - 1; ++i)
+    {
+        RTTESTI_CHECK_MSG(*pSrc8 == *pDst8, ("index %u: Dst=%d, Src=%d\n", i, *pDst8, *pSrc8));
+        pSrc8 += 1;
+        pDst8 += 2;
+    }
+
+    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+    RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
+
+    AudioMixBufDestroy(&parent);
+    AudioMixBufDestroy(&child);
+
+    return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
+}
+
+/* Test 16-bit sample conversion (16-bit -> internal -> 16-bit). */
+static int tstConversion16(RTTEST hTest)
+{
+    unsigned        i;
+    uint32_t        cBufSize = 256;
+    PDMPCMPROPS     props;
+
+
+    RTTestSubF(hTest, "Sample conversion 16-bit");
+
+    PDMAUDIOSTREAMCFG cfg_p =
+    {
+        44100,                   /* Hz */
+        1                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF parent;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
+
+    PDMAUDIOSTREAMCFG cfg_c =   /* Upmixing to parent */
+    {
+        22050,                   /* Hz */
+        1                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    rc = DrvAudioStreamCfgToProps(&cfg_c, &props);
+    AssertRC(rc);
+
+    PDMAUDIOMIXBUF child;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &props, cBufSize));
+    RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
+
+    /* 16-bit signed. More or less exclusively used as output, and usually as input, too. */
+    int16_t     samples[16] = { 0xAA, 0xBB, INT16_MIN, INT16_MIN + 1, INT16_MIN / 2, -3, -2, -1,
+                                0, 1, 2, 3, INT16_MAX / 2, INT16_MAX - 1, INT16_MAX, 0 };
+
+    /*
+     * Writing + mixing from child -> parent, sequential.
+     */
+    uint32_t    cbBuf = 256;
+    char        achBuf[256];
+    uint32_t    read, written, mixed, temp;
+
+    //unused//uint32_t cChildFree     = cBufSize;
+    //unused//uint32_t cChildMixed    = 0;
+    uint32_t cSamplesChild  = 16;
+    uint32_t cSamplesParent = cSamplesChild * 2 - 2;
+    uint32_t cSamplesRead   = 0;
+
+    /**** 16-bit signed samples ****/
+    RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 16-bit\n", cfg_c.uHz, cfg_c.cChannels);
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+    RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+    RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
+    temp = AudioMixBufProcessed(&parent);
+    RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
+
+    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
+
+    for (;;)
+    {
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+        if (!read)
+            break;
+        cSamplesRead += read;
+        AudioMixBufFinish(&parent, read);
+    }
+    RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
+
+    /* Check that the samples came out unharmed. Every other sample is interpolated and we ignore it. */
+    /* NB: This also checks that the default volume setting is 0dB attenuation. */
+    int16_t *pSrc16 = &samples[0];
+    int16_t *pDst16 = (int16_t *)achBuf;
+
+    for (i = 0; i < cSamplesChild - 1; ++i)
+    {
+        RTTESTI_CHECK_MSG(*pSrc16 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
+        pSrc16 += 1;
+        pDst16 += 2;
+    }
+
+    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+    RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
+
+    AudioMixBufDestroy(&parent);
+    AudioMixBufDestroy(&child);
+
+    return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
+}
+
+/* Test volume control. */
+static int tstVolume(RTTEST hTest)
+{
+    unsigned        i;
+    uint32_t        cBufSize = 256;
+    PDMPCMPROPS     props;
+
+
+    RTTestSubF(hTest, "Volume control");
+
+    /* Same for parent/child. */
+    PDMAUDIOSTREAMCFG cfg =
+    {
+        44100,                   /* Hz */
+        2                        /* Channels */,
+        AUD_FMT_S16              /* Format */,
+        PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
+    };
+
+    int rc = DrvAudioStreamCfgToProps(&cfg, &props);
+    AssertRC(rc);
+
+    PDMAUDIOVOLUME vol = { false, 0, 0 };   /* Not muted. */
+    PDMAUDIOMIXBUF parent;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
+
+    PDMAUDIOMIXBUF child;
+    RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &props, cBufSize));
+    RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
+
+    /* A few 16-bit signed samples. */
+    int16_t     samples[16] = { INT16_MIN, INT16_MIN + 1, -128, -64, -4, -1, 0, 1,
+                                2, 255, 256, INT16_MAX / 2, INT16_MAX - 2, INT16_MAX - 1, INT16_MAX, 0 };
+
+    /*
+     * Writing + mixing from child -> parent.
+     */
+    uint32_t    cbBuf = 256;
+    char        achBuf[256];
+    uint32_t    read, written, mixed;
+
+    //unused//uint32_t cChildFree     = cBufSize;
+    //unused//uint32_t cChildMixed    = 0;
+    uint32_t cSamplesChild  = 8;
+    uint32_t cSamplesParent = cSamplesChild;
+    uint32_t cSamplesRead;
+    int16_t *pSrc16;
+    int16_t *pDst16;
+
+    /**** Volume control test ****/
+    RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Volume control test %uHz %uch \n", cfg.uHz, cfg.cChannels);
+
+    /* 1) Full volume/0dB attenuation (255). */
+    vol.uLeft = vol.uRight = 255;
+    AudioMixBufSetVolume(&child, &vol);
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+    RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+    RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
+
+    cSamplesRead = 0;
+    for (;;)
+    {
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+        if (!read)
+            break;
+        cSamplesRead += read;
+        AudioMixBufFinish(&parent, read);
+    }
+    RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
+
+    /* Check that at 0dB the samples came out unharmed. */
+    pSrc16 = &samples[0];
+    pDst16 = (int16_t *)achBuf;
+
+    for (i = 0; i < cSamplesParent * 2 /* stereo */; ++i)
+    {
+        RTTESTI_CHECK_MSG(*pSrc16 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
+        ++pSrc16;
+        ++pDst16;
+    }
+    AudioMixBufReset(&child);
+
+    /* 2) Half volume/-6dB attenuation (16 steps down). */
+    vol.uLeft = vol.uRight = 255 - 16;
+    AudioMixBufSetVolume(&child, &vol);
+
+    RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+    RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+    RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
+
+    cSamplesRead = 0;
+    for (;;)
+    {
+        RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+        if (!read)
+            break;
+        cSamplesRead += read;
+        AudioMixBufFinish(&parent, read);
+    }
+    RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
+
+    /* Check that at -6dB the sample values are halved. */
+    pSrc16 = &samples[0];
+    pDst16 = (int16_t *)achBuf;
+
+    for (i = 0; i < cSamplesParent * 2 /* stereo */; ++i)
+    {
+        /* Watch out! For negative values, x >> 1 is not the same as x / 2. */
+        RTTESTI_CHECK_MSG(*pSrc16 >> 1 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
+        ++pSrc16;
+        ++pDst16;
+    }
+
+    AudioMixBufDestroy(&parent);
+    AudioMixBufDestroy(&child);
+
+    return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+    RTR3InitExe(argc, &argv, 0);
+
+    /*
+     * Initialize IPRT and create the test.
+     */
+    RTTEST hTest;
+    int rc = RTTestInitAndCreate("tstAudioMixBuffer", &hTest);
+    if (rc)
+        return rc;
+    RTTestBanner(hTest);
+
+    rc = tstSingle(hTest);
+    if (RT_SUCCESS(rc))
+        rc = tstParentChild(hTest);
+    if (RT_SUCCESS(rc))
+        rc = tstConversion8(hTest);
+    if (RT_SUCCESS(rc))
+        rc = tstConversion16(hTest);
+    if (RT_SUCCESS(rc))
+        rc = tstVolume(hTest);
+
+    /*
+     * Summary
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
diff --git a/src/VBox/Devices/Bus/DevPCI.cpp b/src/VBox/Devices/Bus/DevPCI.cpp
index dd1d977..f49358d 100644
--- a/src/VBox/Devices/Bus/DevPCI.cpp
+++ b/src/VBox/Devices/Bus/DevPCI.cpp
@@ -45,15 +45,15 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_DEV_PCI
-/* Hack to get PCIDEVICEINT declared at the right point - include "PCIInternal.h". */
-#define PCI_INCLUDE_PRIVATE
-#include <VBox/pci.h>
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
+#include <VBox/vmm/pdmpcidev.h>
 #include <VBox/vmm/pdmdev.h>
 #include <VBox/vmm/mm.h>
 #include <iprt/asm.h>
 #include <iprt/assert.h>
 #include <iprt/string.h>
 
+#include "PciInline.h"
 #include "VBoxDD.h"
 
 
@@ -66,7 +66,7 @@
 typedef struct PIIX3State
 {
     /** The PCI device of the bridge. */
-    PCIDEVICE dev;
+    PDMPCIDEV dev;
 } PIIX3State, PIIX3, *PPIIX3;
 
 /**
@@ -77,16 +77,21 @@ typedef struct PCIBus
     /** Bus number. */
     int32_t             iBus;
     /** Start device number. */
-    int32_t             iDevSearch;
+    uint32_t            iDevSearch;
     /** Number of bridges attached to the bus. */
     uint32_t            cBridges;
 
     uint32_t            Alignment0;
 
-    /** Array of PCI devices. */
-    R3PTRTYPE(PPCIDEVICE) devices[256];
+    union
+    {
+        /** Array of PCI devices. */
+        R3PTRTYPE(PPDMPCIDEV) apDevices[256];
+        /** @deprecated   */
+        R3PTRTYPE(PPDMPCIDEV) devices[256];
+    };
     /** Array of bridges attached to the bus. */
-    R3PTRTYPE(PPCIDEVICE *) papBridgesR3;
+    R3PTRTYPE(PPDMPCIDEV *) papBridgesR3;
 
     /** R3 pointer to the device instance. */
     PPDMDEVINSR3        pDevInsR3;
@@ -104,7 +109,7 @@ typedef struct PCIBus
     PCPDMPCIHLPRC       pPciHlpRC;
 
     /** The PCI device for the PCI bridge. */
-    PCIDEVICE           PciDev;
+    PDMPCIDEV           PciDev;
 
 } PCIBUS;
 /** Pointer to a PCIBUS instance. */
@@ -217,15 +222,15 @@ typedef PCIGLOBALS *PPCIGLOBALS;
 *********************************************************************************************************************************/
 RT_C_DECLS_BEGIN
 
-PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTag);
-PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTag);
+PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTag);
+PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTag);
 PDMBOTHCBDECL(int)  pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
 PDMBOTHCBDECL(int)  pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
 PDMBOTHCBDECL(int)  pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
 PDMBOTHCBDECL(int)  pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
 
 #ifdef IN_RING3
-DECLINLINE(PPCIDEVICE) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus);
+DECLINLINE(PPDMPCIDEV) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus);
 #endif
 
 RT_C_DECLS_END
@@ -246,14 +251,14 @@ RT_C_DECLS_END
 
 #ifdef IN_RING3
 
-static void pci_update_mappings(PCIDevice *d)
+static void pci_update_mappings(PDMPCIDEV *d)
 {
     PPCIBUS pBus = d->Int.s.CTX_SUFF(pBus);
     PCIIORegion *r;
     int cmd, i;
     uint32_t last_addr, new_addr, config_ofs;
 
-    cmd = RT_LE2H_U16(*(uint16_t *)(d->config + PCI_COMMAND));
+    cmd = RT_LE2H_U16(*(uint16_t *)(d->abConfig + PCI_COMMAND));
     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->Int.s.aIORegions[i];
         if (i == PCI_ROM_SLOT) {
@@ -264,7 +269,7 @@ static void pci_update_mappings(PCIDevice *d)
         if (r->size != 0) {
             if (r->type & PCI_ADDRESS_SPACE_IO) {
                 if (cmd & PCI_COMMAND_IO) {
-                    new_addr = RT_LE2H_U32(*(uint32_t *)(d->config +
+                    new_addr = RT_LE2H_U32(*(uint32_t *)(d->abConfig +
                                                          config_ofs));
                     new_addr = new_addr & ~(r->size - 1);
                     last_addr = new_addr + r->size - 1;
@@ -278,7 +283,7 @@ static void pci_update_mappings(PCIDevice *d)
                 }
             } else {
                 if (cmd & PCI_COMMAND_MEMORY) {
-                    new_addr = RT_LE2H_U32(*(uint32_t *)(d->config +
+                    new_addr = RT_LE2H_U32(*(uint32_t *)(d->abConfig +
                                                          config_ofs));
                     /* the ROM slot has a specific enable bit */
                     if (i == PCI_ROM_SLOT && !(new_addr & 1))
@@ -299,7 +304,7 @@ static void pci_update_mappings(PCIDevice *d)
                     new_addr = ~0U;
                 }
             }
-            //LogRel(("PCI: config dev %u/%u BAR%i uOld=%#018llx uNew=%#018llx size=%llu\n", d->devfn >> 3, d->devfn & 7, i, r->addr, new_addr, r->size));
+            //LogRel(("PCI: config dev %u/%u BAR%i uOld=%#018llx uNew=%#018llx size=%llu\n", d->uDevFn >> 3, d->uDevFn & 7, i, r->addr, new_addr, r->size));
             /* now do the real mapping */
             if (new_addr != r->addr) {
                 if (r->addr != ~0U) {
@@ -307,32 +312,32 @@ static void pci_update_mappings(PCIDevice *d)
                         int devclass;
                         /* NOTE: specific hack for IDE in PC case:
                            only one byte must be mapped. */
-                        devclass = d->config[0x0a] | (d->config[0x0b] << 8);
+                        devclass = d->abConfig[0x0a] | (d->abConfig[0x0b] << 8);
                         if (devclass == 0x0101 && r->size == 4) {
-                            int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr + 2, 1);
+                            int rc = PDMDevHlpIOPortDeregister(d->Int.s.CTX_SUFF(pDevIns), r->addr + 2, 1);
                             AssertRC(rc);
                         } else {
-                            int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr, r->size);
+                            int rc = PDMDevHlpIOPortDeregister(d->Int.s.CTX_SUFF(pDevIns), r->addr, r->size);
                             AssertRC(rc);
                         }
                     } else {
                         RTGCPHYS GCPhysBase = r->addr;
                         int rc;
-                        if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, d->pDevIns, GCPhysBase))
+                        if (pBus->pPciHlpR3->pfnIsMMIOExBase(pBus->pDevInsR3, d->Int.s.CTX_SUFF(pDevIns), GCPhysBase))
                         {
                             /* unmap it. */
-                            rc = r->map_func(d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
+                            rc = r->map_func(d->Int.s.pDevInsR3, d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
                             AssertRC(rc);
-                            rc = PDMDevHlpMMIO2Unmap(d->pDevIns, i, GCPhysBase);
+                            rc = PDMDevHlpMMIOExUnmap(d->Int.s.CTX_SUFF(pDevIns), d, i, GCPhysBase);
                         }
                         else
-                            rc = PDMDevHlpMMIODeregister(d->pDevIns, GCPhysBase, r->size);
-                        AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->name, i, GCPhysBase, r->size));
+                            rc = PDMDevHlpMMIODeregister(d->Int.s.CTX_SUFF(pDevIns), GCPhysBase, r->size);
+                        AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->pszNameR3, i, GCPhysBase, r->size));
                     }
                 }
                 r->addr = new_addr;
                 if (r->addr != ~0U) {
-                    int rc = r->map_func(d, i,
+                    int rc = r->map_func(d->Int.s.pDevInsR3, d, i,
                                          r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : 0),
                                          r->size, (PCIADDRESSSPACE)(r->type));
                     AssertRC(rc);
@@ -343,26 +348,28 @@ static void pci_update_mappings(PCIDevice *d)
 }
 
 
-static DECLCALLBACK(uint32_t) pci_default_read_config(PCIDevice *d, uint32_t address, unsigned len)
+static DECLCALLBACK(uint32_t) pci_default_read_config(PPDMDEVINS pDevIns, PDMPCIDEV *d, uint32_t address, unsigned len)
 {
+    NOREF(pDevIns);
     uint32_t val;
     switch(len) {
     case 1:
-        val = d->config[address];
+        val = d->abConfig[address];
         break;
     case 2:
-        val = RT_LE2H_U16(*(uint16_t *)(d->config + address));
+        val = RT_LE2H_U16(*(uint16_t *)(d->abConfig + address));
         break;
     default:
     case 4:
-        val = RT_LE2H_U32(*(uint32_t *)(d->config + address));
+        val = RT_LE2H_U32(*(uint32_t *)(d->abConfig + address));
         break;
     }
     return val;
 }
 
-static DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, unsigned len)
+static DECLCALLBACK(void) pci_default_write_config(PPDMDEVINS pDevIns, PDMPCIDEV *d, uint32_t address, uint32_t val, unsigned len)
 {
+    NOREF(pDevIns);
     int can_write;
     unsigned i;
     uint32_t end, addr;
@@ -388,7 +395,7 @@ static DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t addres
             val &= ~(r->size - 1);
             val |= r->type;
         }
-        *(uint32_t *)(d->config + address) = RT_H2LE_U32(val);
+        *(uint32_t *)(d->abConfig + address) = RT_H2LE_U32(val);
         pci_update_mappings(d);
         return;
     }
@@ -397,7 +404,7 @@ static DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t addres
     addr = address;
     for(i = 0; i < len; i++) {
         /* default read/write accesses */
-        switch(d->config[0x0e]) {
+        switch(d->abConfig[0x0e]) {
         case 0x00: /* normal device */
         case 0x80: /* multi-function device */
             switch(addr) {
@@ -452,26 +459,26 @@ static DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t addres
         {
             /* don't change reserved bits (11-15) */
             val &= ~UINT32_C(0xf8);
-            d->config[addr] = val;
+            d->abConfig[addr] = val;
         }
         else if (addr == 0x06)  /* Status register, bits 0-7. */
         {
             /* don't change read-only bits => actually all lower bits are read-only */
             val &= ~UINT32_C(0xff);
             /* status register, low part: clear bits by writing a '1' to the corresponding bit */
-            d->config[addr] &= ~val;
+            d->abConfig[addr] &= ~val;
         }
         else if (addr == 0x07)  /* Status register, bits 8-15. */
         {
             /* don't change read-only bits */
             val &= ~UINT32_C(0x06);
             /* status register, high part: clear bits by writing a '1' to the corresponding bit */
-            d->config[addr] &= ~val;
+            d->abConfig[addr] &= ~val;
         }
         else
 #endif
         if (can_write) {
-            d->config[addr] = val;
+            d->abConfig[addr] = val;
         }
         addr++;
         val >>= 8;
@@ -507,11 +514,11 @@ static int pci_data_write(PPCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int
         if (pGlobals->PciBus.cBridges)
         {
 #ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
-            PPCIDEVICE pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
+            PPDMPCIDEV pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
             if (pBridgeDevice)
             {
                 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
-                pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, val, len);
+                pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice, config_addr, val, len);
             }
 #else
             RT_NOREF2(val, len);
@@ -521,12 +528,12 @@ static int pci_data_write(PPCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int
     }
     else
     {
-        R3PTRTYPE(PCIDevice *) pci_dev = pGlobals->PciBus.devices[iDevice];
+        R3PTRTYPE(PDMPCIDEV *) pci_dev = pGlobals->PciBus.devices[iDevice];
         if (pci_dev)
         {
 #ifdef IN_RING3
-            Log(("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len));
-            pci_dev->Int.s.pfnConfigWrite(pci_dev, config_addr, val, len);
+            Log(("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->pszNameR3, config_addr, val, len));
+            pci_dev->Int.s.pfnConfigWrite(pci_dev->Int.s.CTX_SUFF(pDevIns), pci_dev, config_addr, val, len);
 #else
             return VINF_IOM_R3_IOPORT_WRITE;
 #endif
@@ -554,11 +561,11 @@ static int pci_data_read(PPCIGLOBALS pGlobals, uint32_t addr, int len, uint32_t
         if (pGlobals->PciBus.cBridges)
         {
 #ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
-            PPCIDEVICE pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
+            PPDMPCIDEV pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
             if (pBridgeDevice)
             {
                 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
-                *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, len);
+                *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice, config_addr, len);
             }
 #else
             NOREF(len);
@@ -568,12 +575,12 @@ static int pci_data_read(PPCIGLOBALS pGlobals, uint32_t addr, int len, uint32_t
     }
     else
     {
-        R3PTRTYPE(PCIDevice *) pci_dev = pGlobals->PciBus.devices[iDevice];
+        R3PTRTYPE(PDMPCIDEV *) pci_dev = pGlobals->PciBus.devices[iDevice];
         if (pci_dev)
         {
 #ifdef IN_RING3
-            *pu32 = pci_dev->Int.s.pfnConfigRead(pci_dev, config_addr, len);
-            Log(("pci_config_read: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, *pu32, len));
+            *pu32 = pci_dev->Int.s.pfnConfigRead(pci_dev->Int.s.CTX_SUFF(pDevIns), pci_dev, config_addr, len);
+            Log(("pci_config_read: %s: addr=%02x val=%08x len=%d\n", pci_dev->pszNameR3, config_addr, *pu32, len));
 #else
             NOREF(len);
             return VINF_IOM_R3_IOPORT_READ;
@@ -607,7 +614,7 @@ static inline int get_pci_irq_apic_level(PPCIGLOBALS pGlobals, int irq_num)
     return (pGlobals->pci_apic_irq_levels[irq_num] != 0);
 }
 
-static void apic_set_irq(PPCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel, int acpi_irq, uint32_t uTagSrc)
+static void apic_set_irq(PPCIBUS pBus, uint8_t uDevFn, PDMPCIDEV *pPciDev, int irq_num1, int iLevel, int acpi_irq, uint32_t uTagSrc)
 {
     /* This is only allowed to be called with a pointer to the host bus. */
     AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
@@ -625,7 +632,7 @@ static void apic_set_irq(PPCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int i
         apic_irq = irq_num + 0x10;
         apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
         Log3(("apic_set_irq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d\n",
-              R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
+              R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num));
         pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
 
         if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
@@ -633,12 +640,12 @@ static void apic_set_irq(PPCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int i
             pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
             apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
             Log3(("apic_set_irq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d (flop)\n",
-                  R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
+                  R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num));
             pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
         }
     } else {
         Log3(("apic_set_irq: %s: irq_num1=%d level=%d acpi_irq=%d\n",
-              R3STRING(pPciDev->name), irq_num1, iLevel, acpi_irq));
+              R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, acpi_irq));
         pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), acpi_irq, iLevel, uTagSrc);
     }
 }
@@ -657,15 +664,15 @@ DECLINLINE(int) get_pci_irq_level(PPCIGLOBALS pGlobals, int irq_num)
  * @param   iIrq            IRQ number to set.
  * @param   iLevel          IRQ level.
  * @param   uTagSrc         The IRQ tag and source ID (for tracing).
- * @remark  uDevFn and pPciDev->devfn are not the same if the device is behind a bridge.
- *          In that case uDevFn will be the slot of the bridge which is needed to calculate the
- *          PIRQ value.
+ * @remark  uDevFn and pPciDev->uDevFn are not the same if the device is behind
+ *          a bridge. In that case uDevFn will be the slot of the bridge which
+ *          is needed to calculate the PIRQ value.
  */
-static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
+static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
 {
     PPCIBUS     pBus =     &pGlobals->PciBus;
-    uint8_t    *pbCfg = pGlobals->PIIX3State.dev.config;
-    const bool  fIsAcpiDevice = pPciDev->config[2] == 0x13 && pPciDev->config[3] == 0x71;
+    uint8_t    *pbCfg = pGlobals->PIIX3State.dev.abConfig;
+    const bool  fIsAcpiDevice = pPciDev->abConfig[2] == 0x13 && pPciDev->abConfig[3] == 0x71;
     /* If the two configuration space bytes at 0xde, 0xad are set to 0xbe, 0xef, a back door
      * is opened to route PCI interrupts directly to the I/O APIC and bypass the PIC.
      * See the \_SB_.PCI0._PRT method in vbox.dsl.
@@ -689,7 +696,7 @@ static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE p
                  * kludge (i.e. we fetch the hardwired value from ACPIs
                  * PCI device configuration space).
                  */
-                apic_set_irq(pBus, uDevFn, pPciDev, -1, iLevel, pPciDev->config[PCI_INTERRUPT_LINE], uTagSrc);
+                apic_set_irq(pBus, uDevFn, pPciDev, -1, iLevel, pPciDev->abConfig[PCI_INTERRUPT_LINE], uTagSrc);
             else
                 apic_set_irq(pBus, uDevFn, pPciDev, iIrq, iLevel, -1, uTagSrc);
             return;
@@ -698,7 +705,7 @@ static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE p
         if (fIsAcpiDevice)
         {
             /* As per above treat ACPI in a special way */
-            pic_irq = pPciDev->config[PCI_INTERRUPT_LINE];
+            pic_irq = pPciDev->abConfig[PCI_INTERRUPT_LINE];
             pGlobals->acpi_irq = pic_irq;
             pGlobals->acpi_irq_level = iLevel & PDM_IRQ_LEVEL_HIGH;
         }
@@ -740,7 +747,7 @@ static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE p
             pic_level |= pGlobals->acpi_irq_level;
 
         Log3(("pciSetIrq: %s: iLevel=%d iIrq=%d pic_irq=%d pic_level=%d uTagSrc=%#x\n",
-              R3STRING(pPciDev->name), iLevel, iIrq, pic_irq, pic_level, uTagSrc));
+              R3STRING(pPciDev->pszNameR3), iLevel, iIrq, pic_irq, pic_level, uTagSrc));
         pBus->CTX_SUFF(pPciHlp)->pfnIsaSetIrq(pBus->CTX_SUFF(pDevIns), pic_irq, pic_level, uTagSrc);
 
         /** @todo optimize pci irq flip-flop some rainy day. */
@@ -753,9 +760,9 @@ static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE p
 /**
  * @interface_method_impl{PDMPCIBUSREG,pfnSetIrqR3}
  */
-PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
+PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
 {
-    pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel, uTagSrc);
+    pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), pPciDev->uDevFn, pPciDev, iIrq, iLevel, uTagSrc);
 }
 
 #ifdef IN_RING3
@@ -768,7 +775,7 @@ PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq,
  * @param  pBus    Pointer to the bus to search on.
  * @param  iBus    Destination bus number.
  */
-DECLINLINE(PPCIDEVICE) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus)
+DECLINLINE(PPDMPCIDEV) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus)
 {
     /* Search for a fitting bridge. */
     for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
@@ -777,12 +784,12 @@ DECLINLINE(PPCIDEVICE) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus)
          * Examine secondary and subordinate bus number.
          * If the target bus is in the range we pass the request on to the bridge.
          */
-        PPCIDEVICE pBridgeTemp = pBus->papBridgesR3[iBridge];
+        PPDMPCIDEV pBridgeTemp = pBus->papBridgesR3[iBridge];
         AssertMsg(pBridgeTemp && pciDevIsPci2PciBridge(pBridgeTemp),
                   ("Device is not a PCI bridge but on the list of PCI bridges\n"));
 
-        if (   iBus >= pBridgeTemp->config[VBOX_PCI_SECONDARY_BUS]
-            && iBus <= pBridgeTemp->config[VBOX_PCI_SUBORDINATE_BUS])
+        if (   iBus >= pBridgeTemp->abConfig[VBOX_PCI_SECONDARY_BUS]
+            && iBus <= pBridgeTemp->abConfig[VBOX_PCI_SUBORDINATE_BUS])
             return pBridgeTemp;
     }
 
@@ -792,7 +799,7 @@ DECLINLINE(PPCIDEVICE) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus)
 
 static void pciR3Piix3Reset(PIIX3State *d)
 {
-    uint8_t *pci_conf = d->dev.config;
+    uint8_t *pci_conf = d->dev.abConfig;
 
     pci_conf[0x04] = 0x07; /* master, memory and I/O */
     pci_conf[0x05] = 0x00;
@@ -1234,6 +1241,19 @@ PDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT
 
 #ifdef IN_RING3
 
+/*
+ * Include code we share with the other PCI bus implementation.
+ *
+ * Note! No #ifdefs, use instant data booleans/flags/whatever.  Goal is to
+ *       completely merge these files!  File #1 contains code we write, where
+ *       as a possible file #2 contains external code if there's any left.
+ */
+typedef PPCIBUS PPCIMERGEDBUS;
+# define pciR3UnmergedConfigReadDev  pci_default_read_config
+# define pciR3UnmergedConfigWriteDev pci_default_write_config
+# include "DevPciMerge1.cpp.h"
+
+
 /* -=-=-=-=-=- Saved state -=-=-=-=-=- */
 
 /**
@@ -1250,11 +1270,11 @@ static int pciR3CommonSaveExec(PPCIBUS pBus, PSSMHANDLE pSSM)
      */
     for (uint32_t i = 0; i < RT_ELEMENTS(pBus->devices); i++)
     {
-        PPCIDEVICE pDev = pBus->devices[i];
+        PPDMPCIDEV pDev = pBus->devices[i];
         if (pDev)
         {
             SSMR3PutU32(pSSM, i);
-            SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
+            SSMR3PutMem(pSSM, pDev->abConfig, sizeof(pDev->abConfig));
 
             int rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
             if (RT_FAILURE(rc))
@@ -1306,7 +1326,7 @@ static DECLCALLBACK(int) pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
  * @param   pbSrcConfig         The configuration register values to be loaded.
  * @param   fIsBridge           Whether this is a bridge device or not.
  */
-static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
+static void pciR3CommonRestoreConfig(PPDMPCIDEV pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
 {
     /*
      * This table defines the fields for normal devices and bridge devices, and
@@ -1403,7 +1423,7 @@ static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig
      * Loop thru the fields covering the 64 bytes of standard registers.
      */
     uint8_t const fBridge = fIsBridge ? 2 : 1;
-    uint8_t *pbDstConfig = &pDev->config[0];
+    uint8_t *pbDstConfig = &pDev->abConfig[0];
     for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
         if (s_aFields[i].fBridge & fBridge)
         {
@@ -1437,14 +1457,14 @@ static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig
                 {
                     if (!s_aFields[i].fWritable)
                         LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
-                                pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
+                                pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
                     else
                         LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
-                                pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
+                                pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
                 }
                 if (off == VBOX_PCI_COMMAND)
                     PCIDevSetCommand(pDev, 0); /* For remapping, see pciR3CommonLoadExec. */
-                pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
+                pDev->Int.s.pfnConfigWrite(pDev->Int.s.CTX_SUFF(pDevIns), pDev, off, u32Src, cb);
             }
         }
 
@@ -1455,11 +1475,11 @@ static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig
      * of the registers, so the device is responsible for correctly
      * restoring functionality governed by these registers.
      */
-    for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
+    for (uint32_t off = 0x40; off < sizeof(pDev->abConfig); off++)
         if (pbDstConfig[off] != pbSrcConfig[off])
         {
             LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
-                    pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
+                    pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
             pbDstConfig[off] = pbSrcConfig[off];
         }
 }
@@ -1492,11 +1512,11 @@ static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint
      */
     for (i = 0; i < RT_ELEMENTS(pBus->devices); i++)
     {
-        PPCIDEVICE pDev = pBus->devices[i];
+        PPDMPCIDEV pDev = pBus->devices[i];
         if (pDev)
         {
             uint16_t u16 = PCIDevGetCommand(pDev);
-            pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
+            pDev->Int.s.pfnConfigWrite(pDev->Int.s.CTX_SUFF(pDevIns), pDev, VBOX_PCI_COMMAND, 0, 2);
             PCIDevSetCommand(pDev, u16);
             Assert(PCIDevGetCommand(pDev) == u16);
         }
@@ -1507,8 +1527,8 @@ static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint
      */
     for (i = 0;; i++)
     {
-        PCIDEVICE   DevTmp;
-        PPCIDEVICE  pDev;
+        PDMPCIDEV   DevTmp;
+        PPDMPCIDEV  pDev;
 
         /* index / terminator */
         rc = SSMR3GetU32(pSSM, &u32);
@@ -1528,17 +1548,17 @@ static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint
         {
             if (pBus->devices[i])
             {
-                LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pBus->devices[i]->name,
+                LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pBus->devices[i]->pszNameR3,
                         PCIDevGetVendorId(pBus->devices[i]), PCIDevGetDeviceId(pBus->devices[i])));
                 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
                     return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
-                                            i, pBus->devices[i]->name, PCIDevGetVendorId(pBus->devices[i]), PCIDevGetDeviceId(pBus->devices[i]));
+                                            i, pBus->devices[i]->pszNameR3, PCIDevGetVendorId(pBus->devices[i]), PCIDevGetDeviceId(pBus->devices[i]));
             }
         }
 
         /* get the data */
         DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
-        SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
+        SSMR3GetMem(pSSM, DevTmp.abConfig, sizeof(DevTmp.abConfig));
         if (uVersion < 3)
         {
             int32_t i32Temp;
@@ -1567,13 +1587,13 @@ static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint
         }
 
         /* match the vendor id assuming that this will never be changed. */
-        if (    DevTmp.config[0] != pDev->config[0]
-            ||  DevTmp.config[1] != pDev->config[1])
+        if (   DevTmp.abConfig[0] != pDev->abConfig[0]
+            || DevTmp.abConfig[1] != pDev->abConfig[1])
             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
-                                     i, pDev->name, DevTmp.config, pDev->config);
+                                    i, pDev->pszNameR3, DevTmp.abConfig, pDev->abConfig);
 
         /* commit the loaded device config. */
-        pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
+        pciR3CommonRestoreConfig(pDev, &DevTmp.abConfig[0], false ); /** @todo fix bridge fun! */
 
         pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
     }
@@ -1634,176 +1654,11 @@ static DECLCALLBACK(int) pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint
 
 /* -=-=-=-=-=- PCI Bus Interface Methods (PDMPCIBUSREG) -=-=-=-=-=- */
 
-/**
- * Registers the device with the specified PCI bus.
- *
- * @returns VBox status code.
- * @param   pBus            The bus to register with.
- * @param   iDev            The PCI device ordinal.
- * @param   pPciDev         The PCI device structure.
- * @param   pszName         Pointer to device name (permanent, readonly). For debugging, not unique.
- */
-static int pciR3RegisterDeviceInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
-{
-    /*
-     * Find device slot.
-     */
-    if (iDev < 0)
-    {
-        /*
-         * Special check for the IDE controller which is our function 1 device
-         * before searching.
-         */
-        if (    !strcmp(pszName, "piix3ide")
-            &&  !pBus->devices[9])
-            iDev = 9;
-        /* LPC bus expected to be there by some guests, better make an additional argument to PDM
-           device helpers, but requires significant rewrite */
-        else if (!strcmp(pszName, "lpc")
-             &&  !pBus->devices[0xf8])
-            iDev = 0xf8;
-        else
-        {
-            Assert(!(pBus->iDevSearch % 8));
-            for (iDev = pBus->iDevSearch; iDev < (int)RT_ELEMENTS(pBus->devices)-7; iDev += 8)
-                if (    !pBus->devices[iDev]
-                    &&  !pBus->devices[iDev + 1]
-                    &&  !pBus->devices[iDev + 2]
-                    &&  !pBus->devices[iDev + 3]
-                    &&  !pBus->devices[iDev + 4]
-                    &&  !pBus->devices[iDev + 5]
-                    &&  !pBus->devices[iDev + 6]
-                    &&  !pBus->devices[iDev + 7])
-                    break;
-            if (iDev >= (int)RT_ELEMENTS(pBus->devices))
-            {
-                AssertMsgFailed(("Couldn't find free spot!\n"));
-                return VERR_PDM_TOO_PCI_MANY_DEVICES;
-            }
-        }
-        pciDevClearRequestedDevfunc(pPciDev);
-    }
-    else
-    {
-        /*
-         * An explicit request.
-         *
-         * If the slot is occupied we'll have to relocate the device
-         * currently occupying it first. This can only be done if the
-         * existing device wasn't explicitly assigned. Also we limit
-         * ourselves to function 0 devices.
-         *
-         * If you start setting devices + function in the
-         * config, do it for all pci devices!
-         */
-        //AssertReleaseMsg(iDev > 8 || pBus->iBus != 0, ("iDev=%d pszName=%s\n", iDev, pszName));
-        if (pBus->devices[iDev])
-        {
-            int iDevRel;
-            AssertReleaseMsg(!(iDev % 8), ("PCI Configuration Conflict! iDev=%d pszName=%s clashes with %s\n",
-                                           iDev, pszName, pBus->devices[iDev]->name));
-            if (    pciDevIsRequestedDevfunc(pBus->devices[iDev])
-                ||  (pBus->devices[iDev + 1] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 1]))
-                ||  (pBus->devices[iDev + 2] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 2]))
-                ||  (pBus->devices[iDev + 3] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 3]))
-                ||  (pBus->devices[iDev + 4] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 4]))
-                ||  (pBus->devices[iDev + 5] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 5]))
-                ||  (pBus->devices[iDev + 6] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 6]))
-                ||  (pBus->devices[iDev + 7] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 7])))
-            {
-                AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
-                                        pszName, pBus->devices[iDev]->name, iDev));
-                return VERR_INTERNAL_ERROR;
-            }
-
-            /* Find free slot for the device(s) we're moving and move them. */
-            for (iDevRel = pBus->iDevSearch; iDevRel < (int)RT_ELEMENTS(pBus->devices)-7; iDevRel += 8)
-            {
-                if (    !pBus->devices[iDevRel]
-                    &&  !pBus->devices[iDevRel + 1]
-                    &&  !pBus->devices[iDevRel + 2]
-                    &&  !pBus->devices[iDevRel + 3]
-                    &&  !pBus->devices[iDevRel + 4]
-                    &&  !pBus->devices[iDevRel + 5]
-                    &&  !pBus->devices[iDevRel + 6]
-                    &&  !pBus->devices[iDevRel + 7])
-                {
-                    int i = 0;
-                    for (i = 0; i < 8; i++)
-                    {
-                        if (!pBus->devices[iDev + i])
-                            continue;
-                        Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->devices[iDev + i]->name, iDev + i, iDevRel + i));
-                        pBus->devices[iDevRel + i] = pBus->devices[iDev + i];
-                        pBus->devices[iDevRel + i]->devfn = iDevRel + i;
-                        pBus->devices[iDev + i] = NULL;
-                    }
-                }
-            }
-            if (pBus->devices[iDev])
-            {
-                AssertMsgFailed(("Couldn't find free spot!\n"));
-                return VERR_PDM_TOO_PCI_MANY_DEVICES;
-            }
-        } /* if conflict */
-        pciDevSetRequestedDevfunc(pPciDev);
-    }
-
-    Assert(!pBus->devices[iDev]);
-    pPciDev->devfn                  = iDev;
-    pPciDev->name                   = pszName;
-    pPciDev->Int.s.pBusR3           = pBus;
-    pPciDev->Int.s.pBusR0           = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
-    pPciDev->Int.s.pBusRC           = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
-    pPciDev->Int.s.pfnConfigRead    = pci_default_read_config;
-    pPciDev->Int.s.pfnConfigWrite   = pci_default_write_config;
-    pBus->devices[iDev]             = pPciDev;
-    if (pciDevIsPci2PciBridge(pPciDev))
-    {
-        AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->devices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
-        AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
-                  ("device is a bridge but does not implement read/write functions\n"));
-        pBus->papBridgesR3[pBus->cBridges] = pPciDev;
-        pBus->cBridges++;
-    }
-
-    Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
-         iDev >> 3, iDev & 7, 0x80000000 | (iDev << 8), pszName));
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
- */
-static DECLCALLBACK(int) pciR3Register(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
-{
-    PPCIBUS     pBus = DEVINS_2_PCIBUS(pDevIns);
-
-    /*
-     * Check input.
-     */
-    if (    !pszName
-        ||  !pPciDev
-        ||  iDev >= (int)RT_ELEMENTS(pBus->devices)
-        ||  (iDev >= 0 && iDev <= 8))
-    {
-        AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Register the device.
-     */
-    return pciR3RegisterDeviceInternal(pBus, iDev, pPciDev, pszName);
-}
-
 
 /**
  * @interface_method_impl{PDMPCIBUSREG,pfnIORegionRegisterR3}
  */
-static DECLCALLBACK(int) pciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, RTGCPHYS cbRegion,
+static DECLCALLBACK(int) pciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iRegion, RTGCPHYS cbRegion,
                                                      PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
 {
     NOREF(pDevIns);
@@ -1848,7 +1703,7 @@ static DECLCALLBACK(int) pciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPCIDEV
  * @interface_method_impl{PDMPCIBUSREG,pfnSetConfigCallbacksR3}
  */
 static DECLCALLBACK(void)
-pciR3CommonSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
+pciR3CommonSetConfigCallbacks(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                               PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
 {
     NOREF(pDevIns);
@@ -1893,7 +1748,7 @@ static DECLCALLBACK(int) pciR3FakePCIBIOS(PPDMDEVINS pDevIns)
         /* Set to trigger level. */
         elcr[irq >> 3] |= (1 << (irq & 7));
         /* Activate irq remapping in PIIX3. */
-        pci_config_writeb(pGlobals, 0, pGlobals->PIIX3State.dev.devfn, 0x60 + i, irq);
+        pci_config_writeb(pGlobals, 0, pGlobals->PIIX3State.dev.uDevFn, 0x60 + i, irq);
     }
 
     /* Tell to the PIC. */
@@ -1933,7 +1788,7 @@ static DECLCALLBACK(void) pciR3IrqRouteInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pH
     PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
     NOREF(pszArgs);
 
-    uint16_t router = pGlobals->PIIX3State.dev.devfn;
+    uint16_t router = pGlobals->PIIX3State.dev.uDevFn;
     pHlp->pfnPrintf(pHlp, "PCI interrupt router at: %02X:%02X:%X\n",
                     router >> 8, (router >> 3) & 0x1f, router & 0x7);
 
@@ -1987,7 +1842,7 @@ static void pciR3BusInfo(PPCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRe
 {
     for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->devices); iDev++)
     {
-        PPCIDEVICE pPciDev = pBus->devices[iDev];
+        PPDMPCIDEV pPciDev = pBus->devices[iDev];
         if (pPciDev != NULL)
         {
             pciR3PrintIndent(pHlp, iIndent);
@@ -1998,7 +1853,7 @@ static void pciR3BusInfo(PPCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRe
              */
             pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x%s%s",
                             pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
-                            pPciDev->name,
+                            pPciDev->pszNameR3,
                             pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
                             PCIDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID), PCIDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID),
                             pciDevIsMsiCapable(pPciDev)  ? " MSI" : "",
@@ -2084,7 +1939,7 @@ static void pciR3BusInfo(PPCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRe
         pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
         for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
         {
-            PPCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PPCIBUS);
+            PPCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns), PPCIBUS);
             pciR3BusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
         }
     }
@@ -2193,13 +2048,13 @@ static DECLCALLBACK(int)   pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
     pGlobals->PciBus.pDevInsR3 = pDevIns;
     pGlobals->PciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
     pGlobals->PciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-    pGlobals->PciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns,   sizeof(PPCIDEVICE)
+    pGlobals->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns,   sizeof(PPDMPCIDEV)
                                                                                  * RT_ELEMENTS(pGlobals->PciBus.devices));
 
     PDMPCIBUSREG PciBusReg;
     PPCIBUS      pBus = &pGlobals->PciBus;
     PciBusReg.u32Version              = PDM_PCIBUSREG_VERSION;
-    PciBusReg.pfnRegisterR3           = pciR3Register;
+    PciBusReg.pfnRegisterR3           = pciR3MergedRegister;
     PciBusReg.pfnRegisterMsiR3        = NULL;
     PciBusReg.pfnIORegionRegisterR3   = pciR3CommonIORegionRegister;
     PciBusReg.pfnSetConfigCallbacksR3 = pciR3CommonSetConfigCallbacks;
@@ -2233,10 +2088,9 @@ static DECLCALLBACK(int)   pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
     PCIDevSetClassSub(  &pBus->PciDev,   0x00); /* host2pci */
     PCIDevSetClassBase( &pBus->PciDev,   0x06); /* PCI_bridge */
     PCIDevSetHeaderType(&pBus->PciDev,   0x00);
-
-    pBus->PciDev.pDevIns              = pDevIns;
-    pciDevSetRequestedDevfunc(&pBus->PciDev);
-    pciR3RegisterDeviceInternal(pBus, 0, &pBus->PciDev, "i440FX");
+    rc = PDMDevHlpPCIRegisterEx(pDevIns, &pBus->PciDev, PDMPCIDEVREG_CFG_PRIMARY, 0 /*fFlags*/,
+                                0 /*uPciDevNo*/, 0 /*uPciFunNo*/, "i440FX");
+    AssertLogRelRCReturn(rc, rc);
 
     /* PIIX3 */
     PCIDevSetVendorId(  &pGlobals->PIIX3State.dev, 0x8086); /* Intel */
@@ -2244,10 +2098,9 @@ static DECLCALLBACK(int)   pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
     PCIDevSetClassSub(  &pGlobals->PIIX3State.dev,   0x01); /* PCI_ISA */
     PCIDevSetClassBase( &pGlobals->PIIX3State.dev,   0x06); /* PCI_bridge */
     PCIDevSetHeaderType(&pGlobals->PIIX3State.dev,   0x80); /* PCI_multifunction, generic */
-
-    pGlobals->PIIX3State.dev.pDevIns      = pDevIns;
-    pciDevSetRequestedDevfunc(&pGlobals->PIIX3State.dev);
-    pciR3RegisterDeviceInternal(pBus, 8, &pGlobals->PIIX3State.dev, "PIIX3");
+    rc = PDMDevHlpPCIRegisterEx(pDevIns, &pGlobals->PIIX3State.dev, PDMPCIDEVREG_CFG_NEXT, 0 /*fFlags*/,
+                                1 /*uPciDevNo*/, 0 /*uPciFunNo*/, "PIIX3");
+    AssertLogRelRCReturn(rc, rc);
     pciR3Piix3Reset(&pGlobals->PIIX3State);
 
     pBus->iDevSearch = 16;
@@ -2361,7 +2214,7 @@ const PDMDEVREG g_DevicePCI =
 /**
  * @interface_method_impl{PDMPCIBUSREG,pfnSetIrqR3}
  */
-PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
+PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
 {
     /*
      * The PCI-to-PCI bridge specification defines how the interrupt pins
@@ -2371,15 +2224,15 @@ PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int
      * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
      */
     PPCIBUS    pBus          = PDMINS_2_DATA(pDevIns, PPCIBUS);
-    PPCIDEVICE pPciDevBus    = pPciDev;
+    PPDMPCIDEV pPciDevBus    = pPciDev;
     int        iIrqPinBridge = iIrq;
     uint8_t    uDevFnBridge  = 0;
 
     /* Walk the chain until we reach the host bus. */
     do
     {
-        uDevFnBridge  = pBus->PciDev.devfn;
-        iIrqPinBridge = ((pPciDevBus->devfn >> 3) + iIrqPinBridge) & 3;
+        uDevFnBridge  = pBus->PciDev.uDevFn;
+        iIrqPinBridge = ((pPciDevBus->uDevFn >> 3) + iIrqPinBridge) & 3;
 
         /* Get the parent. */
         pBus = pBus->PciDev.Int.s.CTX_SUFF(pBus);
@@ -2402,23 +2255,23 @@ static DECLCALLBACK(void) pcibridgeR3ConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t i
     LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
 
     /* If the current bus is not the target bus search for the bus which contains the device. */
-    if (iBus != pBus->PciDev.config[VBOX_PCI_SECONDARY_BUS])
+    if (iBus != pBus->PciDev.abConfig[VBOX_PCI_SECONDARY_BUS])
     {
-        PPCIDEVICE pBridgeDevice = pciR3FindBridge(pBus, iBus);
+        PPDMPCIDEV pBridgeDevice = pciR3FindBridge(pBus, iBus);
         if (pBridgeDevice)
         {
             AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
-            pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
+            pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice, u32Address, u32Value, cb);
         }
     }
     else
     {
         /* This is the target bus, pass the write to the device. */
-        PPCIDEVICE pPciDev = pBus->devices[iDevice];
+        PPDMPCIDEV pPciDev = pBus->devices[iDevice];
         if (pPciDev)
         {
-            Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
-            pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
+            Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->pszNameR3, u32Address, u32Value, cb));
+            pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, u32Value, cb);
         }
     }
 }
@@ -2435,23 +2288,23 @@ static DECLCALLBACK(uint32_t) pcibridgeR3ConfigRead(PPDMDEVINSR3 pDevIns, uint8_
     LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
 
     /* If the current bus is not the target bus search for the bus which contains the device. */
-    if (iBus != pBus->PciDev.config[VBOX_PCI_SECONDARY_BUS])
+    if (iBus != pBus->PciDev.abConfig[VBOX_PCI_SECONDARY_BUS])
     {
-        PPCIDEVICE pBridgeDevice = pciR3FindBridge(pBus, iBus);
+        PPDMPCIDEV pBridgeDevice = pciR3FindBridge(pBus, iBus);
         if (pBridgeDevice)
         {
             AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
-            u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
+            u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice, u32Address, cb);
         }
     }
     else
     {
         /* This is the target bus, pass the read to the device. */
-        PPCIDEVICE pPciDev = pBus->devices[iDevice];
+        PPDMPCIDEV pPciDev = pBus->devices[iDevice];
         if (pPciDev)
         {
-            u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
-            Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
+            u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb);
+            Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->pszNameR3, u32Address, u32Value, cb));
         }
     }
 
@@ -2482,31 +2335,6 @@ static DECLCALLBACK(int) pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM
 
 
 /**
- * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
- */
-static DECLCALLBACK(int) pcibridgeR3RegisterDevice(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
-{
-    PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
-
-    /*
-     * Check input.
-     */
-    if (    !pszName
-        ||  !pPciDev
-        ||  iDev >= (int)RT_ELEMENTS(pBus->devices))
-    {
-        AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Register the device.
-     */
-    return pciR3RegisterDeviceInternal(pBus, iDev, pPciDev, pszName);
-}
-
-
-/**
  * @interface_method_impl{PDMDEVREG,pfnReset}
  */
 static DECLCALLBACK(void) pcibridgeR3Reset(PPDMDEVINS pDevIns)
@@ -2514,9 +2342,9 @@ static DECLCALLBACK(void) pcibridgeR3Reset(PPDMDEVINS pDevIns)
     PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
 
     /* Reset config space to default values. */
-    pBus->PciDev.config[VBOX_PCI_PRIMARY_BUS] = 0;
-    pBus->PciDev.config[VBOX_PCI_SECONDARY_BUS] = 0;
-    pBus->PciDev.config[VBOX_PCI_SUBORDINATE_BUS] = 0;
+    pBus->PciDev.abConfig[VBOX_PCI_PRIMARY_BUS] = 0;
+    pBus->PciDev.abConfig[VBOX_PCI_SECONDARY_BUS] = 0;
+    pBus->PciDev.abConfig[VBOX_PCI_SUBORDINATE_BUS] = 0;
 }
 
 
@@ -2572,11 +2400,11 @@ static DECLCALLBACK(int)   pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstanc
     pBus->pDevInsR3 = pDevIns;
     pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
     pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-    pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->devices));
+    pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->devices));
 
     PDMPCIBUSREG PciBusReg;
     PciBusReg.u32Version              = PDM_PCIBUSREG_VERSION;
-    PciBusReg.pfnRegisterR3           = pcibridgeR3RegisterDevice;
+    PciBusReg.pfnRegisterR3           = pcibridgeR3MergedRegisterDevice;
     PciBusReg.pfnRegisterMsiR3        = NULL;
     PciBusReg.pfnIORegionRegisterR3   = pciR3CommonIORegionRegister;
     PciBusReg.pfnSetConfigCallbacksR3 = pciR3CommonSetConfigCallbacks;
@@ -2616,19 +2444,15 @@ static DECLCALLBACK(int)   pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstanc
      */
     PCIDevSetInterruptPin(&pBus->PciDev, 0x00);
 
-    pBus->PciDev.pDevIns                    = pDevIns;
-
-    /* Bridge-specific data */
-    pciDevSetPci2PciBridge(&pBus->PciDev);
-    pBus->PciDev.Int.s.pfnBridgeConfigRead  = pcibridgeR3ConfigRead;
-    pBus->PciDev.Int.s.pfnBridgeConfigWrite = pcibridgeR3ConfigWrite;
-
     /*
      * Register this PCI bridge. The called function will take care on which bus we will get registered.
      */
-    rc = PDMDevHlpPCIRegister(pDevIns, &pBus->PciDev);
+    rc = PDMDevHlpPCIRegisterEx(pDevIns, &pBus->PciDev, PDMPCIDEVREG_CFG_PRIMARY, PDMPCIDEVREG_F_PCI_BRIDGE,
+                                PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, "pcibridge");
     if (RT_FAILURE(rc))
         return rc;
+    pBus->PciDev.Int.s.pfnBridgeConfigRead  = pcibridgeR3ConfigRead;
+    pBus->PciDev.Int.s.pfnBridgeConfigWrite = pcibridgeR3ConfigWrite;
 
     pBus->iDevSearch = 0;
     /*
diff --git a/src/VBox/Devices/Bus/DevPciIch9.cpp b/src/VBox/Devices/Bus/DevPciIch9.cpp
index bb59981..d96c79e 100644
--- a/src/VBox/Devices/Bus/DevPciIch9.cpp
+++ b/src/VBox/Devices/Bus/DevPciIch9.cpp
@@ -23,10 +23,10 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_DEV_PCI
-/* Hack to get PCIDEVICEINT declared at the right point - include "PCIInternal.h". */
-#define PCI_INCLUDE_PRIVATE
-#define PCIBus ICH9PCIBus
-#include <VBox/pci.h>
+#define PCIBus    ICH9PCIBus        /**< HACK ALERT! Real ugly type hack! */
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
+#include <VBox/vmm/pdmpcidev.h>
+
 #include <VBox/msi.h>
 #include <VBox/vmm/pdmdev.h>
 #include <VBox/vmm/mm.h>
@@ -34,9 +34,10 @@
 #include <iprt/assert.h>
 #include <iprt/string.h>
 #ifdef IN_RING3
-#include <iprt/alloc.h>
+# include <iprt/mem.h>
 #endif
 
+#include "PciInline.h"
 #include "VBoxDD.h"
 #include "MsiCommon.h"
 
@@ -55,9 +56,9 @@ typedef struct ICH9PCIBus
     uint32_t            cBridges;
 
     /** Array of PCI devices. We assume 32 slots, each with 8 functions. */
-    R3PTRTYPE(PPCIDEVICE)   apDevices[256];
+    R3PTRTYPE(PPDMPCIDEV)   apDevices[256];
     /** Array of bridges attached to the bus. */
-    R3PTRTYPE(PPCIDEVICE *) papBridgesR3;
+    R3PTRTYPE(PPDMPCIDEV *) papBridgesR3;
 
     /** R3 pointer to the device instance. */
     PPDMDEVINSR3        pDevInsR3;
@@ -75,8 +76,12 @@ typedef struct ICH9PCIBus
     PCPDMPCIHLPRC       pPciHlpRC;
 
     /** The PCI device for the PCI bridge. */
-    PCIDEVICE           aPciDev;
+    PDMPCIDEV           aPciDev;
 
+    /** Start device number - always zero (only for DevPCI source compat). */
+    uint32_t            iDevSearch;
+    /** Size alignemnt padding. */
+    uint32_t            u32Alignment;
 } ICH9PCIBUS, *PICH9PCIBUS;
 
 
@@ -171,14 +176,14 @@ typedef struct
     DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
 
 /* Prototypes */
-static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev,
+static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPDMPCIDEV pPciDev,
                                   int iIrq, int iLevel, uint32_t uTagSrc);
 #ifdef IN_RING3
 static void ich9pcibridgeReset(PPDMDEVINS pDevIns);
-static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName);
-static void ich9pciUpdateMappings(PCIDevice *pDev);
-static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len);
-DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus);
+static void ich9pciUpdateMappings(PDMPCIDEV *pDev);
+static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t u32Address, unsigned len);
+static DECLCALLBACK(void)     ich9pciConfigWriteDev(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t u32Address, uint32_t val, unsigned len);
+DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus);
 static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn);
 #endif
 
@@ -199,13 +204,13 @@ DECLINLINE(void) ich9pciStateToPciAddr(PICH9PCIGLOBALS pGlobals, RTGCPHYS addr,
     pPciAddr->iRegister    = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
 }
 
-PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
+PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
 {
     LogFlowFunc(("invoked by %p/%d: iIrq=%d iLevel=%d uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, iIrq, iLevel, uTagSrc));
-    ich9pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel, uTagSrc);
+    ich9pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS), pPciDev->uDevFn, pPciDev, iIrq, iLevel, uTagSrc);
 }
 
-PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
+PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
 {
     /*
      * The PCI-to-PCI bridge specification defines how the interrupt pins
@@ -215,15 +220,15 @@ PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev,
      * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
      */
     PICH9PCIBUS    pBus          = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
-    PPCIDEVICE     pPciDevBus    = pPciDev;
+    PPDMPCIDEV     pPciDevBus    = pPciDev;
     int            iIrqPinBridge = iIrq;
     uint8_t        uDevFnBridge  = 0;
 
     /* Walk the chain until we reach the host bus. */
     do
     {
-        uDevFnBridge  = pBus->aPciDev.devfn;
-        iIrqPinBridge = ((pPciDevBus->devfn >> 3) + iIrqPinBridge) & 3;
+        uDevFnBridge  = pBus->aPciDev.uDevFn;
+        iIrqPinBridge = ((pPciDevBus->uDevFn >> 3) + iIrqPinBridge) & 3;
 
         /* Get the parent. */
         pBus = pBus->aPciDev.Int.s.CTX_SUFF(pBus);
@@ -324,11 +329,11 @@ static int ich9pciDataWriteAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pAddr,
         if (pGlobals->aPciBus.cBridges)
         {
 #ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
-            PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pAddr->iBus);
+            PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pAddr->iBus);
             if (pBridgeDevice)
             {
                 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
-                pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, pAddr->iBus, pAddr->iDeviceFunc,
+                pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), pAddr->iBus, pAddr->iDeviceFunc,
                                                           pAddr->iRegister, val, cb);
             }
 #else
@@ -338,11 +343,11 @@ static int ich9pciDataWriteAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pAddr,
     }
     else                    /* forward to directly connected device */
     {
-        R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[pAddr->iDeviceFunc];
-        if (aDev)
+        R3PTRTYPE(PDMPCIDEV *) pPciDev = pGlobals->aPciBus.apDevices[pAddr->iDeviceFunc];
+        if (pPciDev)
         {
 #ifdef IN_RING3
-            aDev->Int.s.pfnConfigWrite(aDev, pAddr->iRegister, val, cb);
+            pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, pAddr->iRegister, val, cb);
 #else
             rc = rcReschedule;
 #endif
@@ -437,11 +442,12 @@ static int ich9pciDataReadAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pPciAddr, i
         if (pGlobals->aPciBus.cBridges)
         {
 #ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
-            PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pPciAddr->iBus);
+            PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pPciAddr->iBus);
             if (pBridgeDevice)
             {
                 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
-                *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, pPciAddr->iBus, pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb);
+                *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), pPciAddr->iBus,
+                                                                 pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb);
             }
             else
                 ich9pciNoMem(pu32, cb);
@@ -454,11 +460,11 @@ static int ich9pciDataReadAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pPciAddr, i
     }
     else                    /* forward to directly connected device */
     {
-        R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[pPciAddr->iDeviceFunc];
-        if (aDev)
+        R3PTRTYPE(PDMPCIDEV *) pPciDev = pGlobals->aPciBus.apDevices[pPciAddr->iDeviceFunc];
+        if (pPciDev)
         {
 #ifdef IN_RING3
-            *pu32 = aDev->Int.s.pfnConfigRead(aDev, pPciAddr->iRegister, cb);
+            *pu32 = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, pPciAddr->iRegister, cb);
 #else
             rc = rcReschedule;
 #endif
@@ -569,7 +575,7 @@ DECLINLINE(void) ich9pciApicLevelDown(PICH9PCIGLOBALS pGlobals, int irq_num)
     ASMAtomicDecU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
 }
 
-static void ich9pciApicSetIrq(PICH9PCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel,
+static void ich9pciApicSetIrq(PICH9PCIBUS pBus, uint8_t uDevFn, PDMPCIDEV *pPciDev, int irq_num1, int iLevel,
                               uint32_t uTagSrc, int iForcedIrq)
 {
     /* This is only allowed to be called with a pointer to the root bus. */
@@ -589,7 +595,7 @@ static void ich9pciApicSetIrq(PICH9PCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciD
         apic_irq = irq_num + 0x10;
         apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
         Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x\n",
-              R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
+              R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
         pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
 
         if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
@@ -602,17 +608,17 @@ static void ich9pciApicSetIrq(PICH9PCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciD
             pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
             apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
             Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x (flop)\n",
-                  R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
+                  R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
             pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
         }
     } else {
         Log3(("ich9pciApicSetIrq: (forced) %s: irq_num1=%d level=%d acpi_irq=%d uTagSrc=%#x\n",
-              R3STRING(pPciDev->name), irq_num1, iLevel, iForcedIrq, uTagSrc));
+              R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, iForcedIrq, uTagSrc));
         pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), iForcedIrq, iLevel, uTagSrc);
     }
 }
 
-static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev,
+static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPDMPCIDEV pPciDev,
                                   int iIrq, int iLevel, uint32_t uTagSrc)
 {
     /* If MSI or MSI-X is enabled, PCI INTx# signals are disabled regardless of the PCI command
@@ -770,7 +776,20 @@ PDMBOTHCBDECL(int) ich9pciMcfgMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPH
 
 #ifdef IN_RING3
 
-DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus)
+/*
+ * Include code we share with the other PCI bus implementation.
+ *
+ * Note! No #ifdefs, use instant data booleans/flags/whatever.  Goal is to
+ *       completely merge these files!  File #1 contains code we write, where
+ *       as a possible file #2 contains external code if there's any left.
+ */
+typedef PICH9PCIBUS PPCIMERGEDBUS;
+# define pciR3UnmergedConfigReadDev  ich9pciConfigReadDev
+# define pciR3UnmergedConfigWriteDev ich9pciConfigWriteDev
+# include "DevPciMerge1.cpp.h"
+
+
+DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus)
 {
     /* Search for a fitting bridge. */
     for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
@@ -779,7 +798,7 @@ DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus)
          * Examine secondary and subordinate bus number.
          * If the target bus is in the range we pass the request on to the bridge.
          */
-        PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
+        PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
         AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
                   ("Device is not a PCI bridge but on the list of PCI bridges\n"));
         uint32_t uSecondary   = PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
@@ -793,24 +812,24 @@ DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus)
     return NULL;
 }
 
-static uint32_t ich9pciGetCfg(PCIDevice* aDev, int32_t iRegister, int cb)
+static uint32_t ich9pciGetCfg(PPDMPCIDEV pPciDev, int32_t iRegister, int cb)
 {
-    return aDev->Int.s.pfnConfigRead(aDev, iRegister, cb);
+    return pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, iRegister, cb);
 }
 
-static uint8_t ich9pciGetByte(PCIDevice* aDev, int32_t iRegister)
+static uint8_t ich9pciGetByte(PPDMPCIDEV pPciDev, int32_t iRegister)
 {
-    return (uint8_t)ich9pciGetCfg(aDev, iRegister, 1);
+    return (uint8_t)ich9pciGetCfg(pPciDev, iRegister, 1);
 }
 
-static uint16_t ich9pciGetWord(PCIDevice* aDev, int32_t iRegister)
+static uint16_t ich9pciGetWord(PPDMPCIDEV pPciDev, int32_t iRegister)
 {
-    return (uint16_t)ich9pciGetCfg(aDev, iRegister, 2);
+    return (uint16_t)ich9pciGetCfg(pPciDev, iRegister, 2);
 }
 
-static uint32_t ich9pciGetDWord(PCIDevice* aDev, int32_t iRegister)
+static uint32_t ich9pciGetDWord(PPDMPCIDEV pPciDev, int32_t iRegister)
 {
-    return (uint32_t)ich9pciGetCfg(aDev, iRegister, 4);
+    return (uint32_t)ich9pciGetCfg(pPciDev, iRegister, 4);
 }
 
 DECLINLINE(uint32_t) ich9pciGetRegionReg(int iRegion)
@@ -821,7 +840,7 @@ DECLINLINE(uint32_t) ich9pciGetRegionReg(int iRegion)
 
 #define INVALID_PCI_ADDRESS ~0U
 
-static int  ich9pciUnmapRegion(PPCIDEVICE pDev, int iRegion)
+static int  ich9pciUnmapRegion(PPDMPCIDEV pDev, int iRegion)
 {
     PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
     int rc = VINF_SUCCESS;
@@ -834,21 +853,22 @@ static int  ich9pciUnmapRegion(PPCIDEVICE pDev, int iRegion)
         if (pRegion->type & PCI_ADDRESS_SPACE_IO)
         {
             /* Port IO */
-            rc = PDMDevHlpIOPortDeregister(pDev->pDevIns, pRegion->addr, pRegion->size);
+            rc = PDMDevHlpIOPortDeregister(pDev->Int.s.pDevInsR3, pRegion->addr, pRegion->size);
             AssertRC(rc);
         }
         else
         {
             RTGCPHYS GCPhysBase = pRegion->addr;
-            if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, pDev->pDevIns, GCPhysBase))
+            if (pBus->pPciHlpR3->pfnIsMMIOExBase(pBus->pDevInsR3, pDev->Int.s.pDevInsR3, GCPhysBase))
             {
                 /* unmap it. */
-                rc = pRegion->map_func(pDev, iRegion, NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
+                rc = pRegion->map_func(pDev->Int.s.pDevInsR3, pDev, iRegion,
+                                       NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
                 AssertRC(rc);
-                rc = PDMDevHlpMMIO2Unmap(pDev->pDevIns, iRegion, GCPhysBase);
+                rc = PDMDevHlpMMIOExUnmap(pDev->Int.s.pDevInsR3, pDev, iRegion, GCPhysBase);
             }
             else
-                rc = PDMDevHlpMMIODeregister(pDev->pDevIns, GCPhysBase, pRegion->size);
+                rc = PDMDevHlpMMIODeregister(pDev->Int.s.pDevInsR3, GCPhysBase, pRegion->size);
         }
 
         pRegion->addr = INVALID_PCI_ADDRESS;
@@ -857,7 +877,7 @@ static int  ich9pciUnmapRegion(PPCIDEVICE pDev, int iRegion)
     return rc;
 }
 
-static void ich9pciUpdateMappings(PCIDevice* pDev)
+static void ich9pciUpdateMappings(PDMPCIDEV* pDev)
 {
     uint64_t uLast, uNew;
 
@@ -896,18 +916,8 @@ static void ich9pciUpdateMappings(PCIDevice* pDev)
             if (iCmd & PCI_COMMAND_MEMACCESS)
             {
                 uNew = ich9pciGetDWord(pDev, uConfigReg);
-
                 if (f64Bit)
-                {
-                    uNew |= ((uint64_t)ich9pciGetDWord(pDev, uConfigReg+4)) << 32;
-                    /** @todo r=klaus Is this really true? Needs to be fixed properly. */
-                    if (uNew > UINT64_C(0x0000010000000000))
-                    {
-                        /* Workaround for REM being unhapping with mapping very long 64-bit addresses */
-                        LogRel(("Ignoring too long 64-bit BAR: %llx\n", uNew));
-                        uNew = INVALID_PCI_ADDRESS;
-                    }
-                }
+                    uNew |= (uint64_t)ich9pciGetDWord(pDev, uConfigReg + 4) << 32;
 
                 /* the ROM slot has a specific enable bit */
                 if (iRegion == PCI_ROM_SLOT && !(uNew & 1))
@@ -927,7 +937,7 @@ static void ich9pciUpdateMappings(PCIDevice* pDev)
             } else
                 uNew = INVALID_PCI_ADDRESS;
         }
-        LogRel2(("PCI: config dev %u/%u BAR%i uOld=%#018llx uNew=%#018llx size=%llu\n", pDev->devfn >> 3, pDev->devfn & 7, iRegion, pRegion->addr, uNew, pRegion->size));
+        LogRel2(("PCI: config dev %u/%u BAR%i uOld=%#018llx uNew=%#018llx size=%llu\n", pDev->uDevFn >> 3, pDev->uDevFn & 7, iRegion, pRegion->addr, uNew, pRegion->size));
         /* now do the real mapping */
         if (uNew != pRegion->addr)
         {
@@ -939,7 +949,7 @@ static void ich9pciUpdateMappings(PCIDevice* pDev)
             {
 
                 /* finally, map the region */
-                rc = pRegion->map_func(pDev, iRegion,
+                rc = pRegion->map_func(pDev->Int.s.pDevInsR3, pDev, iRegion,
                                        pRegion->addr, pRegion->size,
                                        (PCIADDRESSSPACE)(pRegion->type));
                 AssertRC(rc);
@@ -951,30 +961,8 @@ static void ich9pciUpdateMappings(PCIDevice* pDev)
     }
 }
 
-static DECLCALLBACK(int) ich9pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
-{
-    PICH9PCIBUS     pBus = DEVINS_2_PCIBUS(pDevIns);
 
-    /*
-     * Check input.
-     */
-    if (    !pszName
-        ||  !pPciDev
-        ||  iDev >= (int)RT_ELEMENTS(pBus->apDevices)
-        )
-    {
-        AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Register the device.
-     */
-    return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
-}
-
-
-static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg)
+static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)
 {
     NOREF(pDevIns);
     int rc;
@@ -991,29 +979,7 @@ static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPCIDEVICE pPciD
 }
 
 
-static DECLCALLBACK(int) ich9pcibridgeRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
-{
-
-    PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
-
-    /*
-     * Check input.
-     */
-    if (    !pszName
-        ||  !pPciDev
-        ||  iDev >= (int)RT_ELEMENTS(pBus->apDevices))
-    {
-        AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Register the device.
-     */
-    return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
-}
-
-static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, RTGCPHYS cbRegion,
+static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iRegion, RTGCPHYS cbRegion,
                                                  PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
 {
     NOREF(pDevIns);
@@ -1039,7 +1005,7 @@ static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE
                     VERR_INVALID_PARAMETER);
 
     Log(("ich9pciIORegionRegister: %s region %d size %RGp type %x\n",
-         pPciDev->name, iRegion, cbRegion, enmType));
+         pPciDev->pszNameR3, iRegion, cbRegion, enmType));
 
     /* Make sure that we haven't marked this region as continuation of 64-bit region. */
     Assert(pPciDev->Int.s.aIORegions[iRegion].type != 0xff);
@@ -1070,7 +1036,7 @@ static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE
     return VINF_SUCCESS;
 }
 
-static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
+static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                                                     PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
 {
     NOREF(pDevIns);
@@ -1091,13 +1057,13 @@ static int ich9pciR3CommonSaveExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM)
      */
     for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
     {
-        PPCIDEVICE pDev = pBus->apDevices[i];
+        PPDMPCIDEV pDev = pBus->apDevices[i];
         if (pDev)
         {
             /* Device position */
             SSMR3PutU32(pSSM, i);
             /* PCI config registers */
-            SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
+            SSMR3PutMem(pSSM, pDev->abConfig, sizeof(pDev->abConfig));
 
             /* Device flags */
             int rc = SSMR3PutU32(pSSM, pDev->Int.s.fFlags);
@@ -1174,21 +1140,22 @@ static DECLCALLBACK(void) ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t
     /* If the current bus is not the target bus search for the bus which contains the device. */
     if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
     {
-        PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
+        PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
         if (pBridgeDevice)
         {
             AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
-            pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
+            pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
+                                                      u32Address, u32Value, cb);
         }
     }
     else
     {
         /* This is the target bus, pass the write to the device. */
-        PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
+        PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
         if (pPciDev)
         {
-            Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
-            pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
+            Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->pszNameR3, u32Address, u32Value, cb));
+            pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, u32Value, cb);
         }
     }
 }
@@ -1203,11 +1170,12 @@ static DECLCALLBACK(uint32_t) ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint
     /* If the current bus is not the target bus search for the bus which contains the device. */
     if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
     {
-        PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
+        PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
         if (pBridgeDevice)
         {
             AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
-            u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
+            u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
+                                                                u32Address, cb);
         }
         else
             ich9pciNoMem(&u32Value, 4);
@@ -1215,11 +1183,11 @@ static DECLCALLBACK(uint32_t) ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint
     else
     {
         /* This is the target bus, pass the read to the device. */
-        PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
+        PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
         if (pPciDev)
         {
-            u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
-            Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
+            u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb);
+            Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->pszNameR3, u32Address, u32Value, cb));
         }
         else
             ich9pciNoMem(&u32Value, 4);
@@ -1236,7 +1204,7 @@ static DECLCALLBACK(uint32_t) ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint
  * @param   pbSrcConfig         The configuration register values to be loaded.
  * @param   fIsBridge           Whether this is a bridge device or not.
  */
-static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
+static void pciR3CommonRestoreConfig(PPDMPCIDEV pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
 {
     /*
      * This table defines the fields for normal devices and bridge devices, and
@@ -1334,7 +1302,7 @@ static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig
      */
     uint8_t const fBridge = fIsBridge ? 2 : 1;
     Assert(!pciDevIsPassthrough(pDev));
-    uint8_t *pbDstConfig = &pDev->config[0];
+    uint8_t *pbDstConfig = &pDev->abConfig[0];
 
     for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
         if (s_aFields[i].fBridge & fBridge)
@@ -1369,14 +1337,14 @@ static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig
                 {
                     if (!s_aFields[i].fWritable)
                         LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
-                                pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
+                                pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
                     else
                         LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
-                                pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
+                                pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
                 }
                 if (off == VBOX_PCI_COMMAND)
                     PCIDevSetCommand(pDev, 0); /* For remapping, see ich9pciR3CommonLoadExec. */
-                pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
+                pDev->Int.s.pfnConfigWrite(pDev->Int.s.CTX_SUFF(pDevIns), pDev, off, u32Src, cb);
             }
         }
 
@@ -1387,11 +1355,11 @@ static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig
      * of the registers, so the device is responsible for correctly
      * restoring functionality governed by these registers.
      */
-    for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
+    for (uint32_t off = 0x40; off < sizeof(pDev->abConfig); off++)
         if (pbDstConfig[off] != pbSrcConfig[off])
         {
             LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
-                    pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
+                    pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
             pbDstConfig[off] = pbSrcConfig[off];
         }
 }
@@ -1425,11 +1393,11 @@ static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pS
      */
     for (i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
     {
-        PPCIDEVICE pDev = pBus->apDevices[i];
+        PPDMPCIDEV pDev = pBus->apDevices[i];
         if (pDev)
         {
             uint16_t u16 = PCIDevGetCommand(pDev);
-            pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
+            pDev->Int.s.pfnConfigWrite(pDev->Int.s.CTX_SUFF(pDevIns), pDev, VBOX_PCI_COMMAND, 0, 2);
             PCIDevSetCommand(pDev, u16);
             Assert(PCIDevGetCommand(pDev) == u16);
         }
@@ -1443,8 +1411,8 @@ static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pS
      */
     for (i = 0;; i++)
     {
-        PPCIDEVICE  pDev;
-        PCIDEVICE   DevTmp;
+        PPDMPCIDEV  pDev;
+        PDMPCIDEV   DevTmp;
 
         /* index / terminator */
         rc = SSMR3GetU32(pSSM, &u32);
@@ -1460,12 +1428,12 @@ static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pS
             pDev = pBus->apDevices[i];
             if (pDev)
             {
-                LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pDev->name,
+                LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pDev->pszNameR3,
                         PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev)));
                 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
                 {
                     rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
-                                          i, pDev->name, PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev));
+                                          i, pDev->pszNameR3, PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev));
                     break;
                 }
             }
@@ -1480,7 +1448,7 @@ static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pS
         DevTmp.Int.s.u8MsixCapOffset = 0;
         DevTmp.Int.s.u8MsixCapSize = 0;
         DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
-        SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
+        SSMR3GetMem(pSSM, DevTmp.abConfig, sizeof(DevTmp.abConfig));
 
         SSMR3GetU32(pSSM, &DevTmp.Int.s.fFlags);
         SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
@@ -1519,13 +1487,13 @@ static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pS
         if (PCIDevGetVendorId(&DevTmp) != PCIDevGetVendorId(pDev))
         {
             rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
-                                  i, pDev->name, PCIDevGetVendorId(&DevTmp), PCIDevGetVendorId(pDev));
+                                  i, pDev->pszNameR3, PCIDevGetVendorId(&DevTmp), PCIDevGetVendorId(pDev));
             break;
         }
 
         /* commit the loaded device config. */
         Assert(!pciDevIsPassthrough(pDev));
-        pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
+        pciR3CommonRestoreConfig(pDev, &DevTmp.abConfig[0], false ); /** @todo fix bridge fun! */
 
         pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
         pDev->Int.s.u8MsiCapOffset  = DevTmp.Int.s.u8MsiCapOffset;
@@ -1889,7 +1857,7 @@ static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
             PICH9PCIBUS pBus = &pGlobals->aPciBus;
             while (1)
             {
-                PPCIDEVICE pBridge = ich9pciFindBridge(pBus, uBus);
+                PPDMPCIDEV pBridge = ich9pciFindBridge(pBus, uBus);
                 if (!pBridge)
                 {
                     Assert(false);
@@ -1900,7 +1868,7 @@ static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
                     /* OK, found bus this device attached to. */
                     break;
                 }
-                pBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
+                pBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PICH9PCIBUS);
             }
 
             /* We need to go up to the host bus to see which irq pin this
@@ -1909,7 +1877,7 @@ static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
             while (pBus->iBus != 0)
             {
                 /* Get the pin the device would assert on the bridge. */
-                iPin = ((pBus->aPciDev.devfn >> 3) + iPin) & 3;
+                iPin = ((pBus->aPciDev.uDevFn >> 3) + iPin) & 3;
                 pBus = pBus->aPciDev.Int.s.pBusR3;
             };
         }
@@ -1933,7 +1901,7 @@ static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
 static void ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS pBus, unsigned uBusPrimary,
                                       unsigned uBusSecondary)
 {
-    PPCIDEVICE pBridgeDev = &pBus->aPciDev;
+    PPDMPCIDEV pBridgeDev = &pBus->aPciDev;
 
     /* Set only if we are not on the root bus, it has no primary bus attached. */
     if (uBusSecondary != 0)
@@ -1944,10 +1912,10 @@ static void ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS pBus
 
     for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
     {
-        PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
+        PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
         AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
                   ("Device is not a PCI bridge but on the list of PCI bridges\n"));
-        PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
+        PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PICH9PCIBUS);
         pGlobals->uBus++;
         ich9pciInitBridgeTopology(pGlobals, pChildBus, uBusSecondary, pGlobals->uBus);
     }
@@ -2004,31 +1972,32 @@ static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
  * Configuration space read callback (PCIDEVICEINT::pfnConfigRead) for
  * connected devices.
  */
-static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len)
+static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t u32Address, unsigned len)
 {
+    NOREF(pDevIns);
     if ((u32Address + len) > 256 && (u32Address + len) < 4096)
     {
         LogRel(("PCI: %8s/%u: Read from extended register %d fallen back to generic code\n",
-                aDev->name, aDev->pDevIns->iInstance, u32Address));
+                pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, u32Address));
         return 0;
     }
 
     AssertMsgReturn(u32Address + len <= 256, ("Read after the end of PCI config space\n"),
                     0);
-    if (   pciDevIsMsiCapable(aDev)
-        && (u32Address >= aDev->Int.s.u8MsiCapOffset)
-        && (u32Address < (unsigned)(aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize))
+    if (   pciDevIsMsiCapable(pPciDev)
+        && (u32Address >= pPciDev->Int.s.u8MsiCapOffset)
+        && (u32Address < (unsigned)(pPciDev->Int.s.u8MsiCapOffset + pPciDev->Int.s.u8MsiCapSize))
        )
     {
-        return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
+        return MsiPciConfigRead(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), pPciDev, u32Address, len);
     }
 
-    if (   pciDevIsMsixCapable(aDev)
-        && (u32Address >= aDev->Int.s.u8MsixCapOffset)
-        && (u32Address < (unsigned)(aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize))
+    if (   pciDevIsMsixCapable(pPciDev)
+        && (u32Address >= pPciDev->Int.s.u8MsixCapOffset)
+        && (u32Address < (unsigned)(pPciDev->Int.s.u8MsixCapOffset + pPciDev->Int.s.u8MsixCapSize))
        )
     {
-        return MsixPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
+        return MsixPciConfigRead(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), pPciDev, u32Address, len);
     }
 
     AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
@@ -2036,11 +2005,11 @@ static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32
     switch (len)
     {
         case 1:
-            return PCIDevGetByte(aDev,  u32Address);
+            return PCIDevGetByte(pPciDev,  u32Address);
         case 2:
-            return PCIDevGetWord(aDev,  u32Address);
+            return PCIDevGetWord(pPciDev,  u32Address);
         case 4:
-            return PCIDevGetDWord(aDev, u32Address);
+            return PCIDevGetDWord(pPciDev, u32Address);
         default:
             Assert(false);
             return 0;
@@ -2048,9 +2017,9 @@ static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32
 }
 
 
-DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset, uint8_t u8Val)
+DECLINLINE(void) ich9pciWriteBarByte(PPDMPCIDEV pPciDev, int iRegion, int iOffset, uint8_t u8Val)
 {
-    PCIIORegion * pRegion = &aDev->Int.s.aIORegions[iRegion];
+    PCIIORegion * pRegion = &pPciDev->Int.s.aIORegions[iRegion];
     int64_t iRegionSize = pRegion->size;
 
     Log3(("ich9pciWriteBarByte: region=%d off=%d val=%x size=%d\n",
@@ -2062,7 +2031,7 @@ DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset,
     /* Check if we're writing to upper part of 64-bit BAR. */
     if (pRegion->type == 0xff)
     {
-        ich9pciWriteBarByte(aDev, iRegion-1, iOffset+4, u8Val);
+        ich9pciWriteBarByte(pPciDev, iRegion-1, iOffset+4, u8Val);
         return;
     }
 
@@ -2083,12 +2052,12 @@ DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset,
 
     }
 
-    uint8_t u8Old = PCIDevGetByte(aDev, uAddr) & uMask;
+    uint8_t u8Old = PCIDevGetByte(pPciDev, uAddr) & uMask;
     u8Val = (u8Old & uMask) | (u8Val & ~uMask);
 
     Log3(("ich9pciWriteBarByte: was %x writing %x\n", u8Old, u8Val));
 
-    PCIDevSetByte(aDev, uAddr, u8Val);
+    PCIDevSetByte(pPciDev, uAddr, u8Val);
 }
 
 
@@ -2099,47 +2068,48 @@ DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset,
  * See paragraph 7.5 of PCI Express specification (p. 349) for
  * definition of registers and their writability policy.
  */
-static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Address,
-                                                uint32_t val, unsigned len)
+static DECLCALLBACK(void) ich9pciConfigWriteDev(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
+                                                uint32_t u32Address, uint32_t val, unsigned len)
 {
+    NOREF(pDevIns);
     Assert(len <= 4);
 
     if ((u32Address + len) > 256 && (u32Address + len) < 4096)
     {
         LogRel(("PCI: %8s/%u: Write to extended register %d fallen back to generic code\n",
-                aDev->name, aDev->pDevIns->iInstance, u32Address));
+                pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, u32Address));
         return;
     }
 
     AssertMsgReturnVoid(u32Address + len <= 256, ("Write after end of PCI config space\n"));
 
-    if (   pciDevIsMsiCapable(aDev)
-        && (u32Address >= aDev->Int.s.u8MsiCapOffset)
-        && (u32Address < (unsigned)(aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize))
+    if (   pciDevIsMsiCapable(pPciDev)
+        && (u32Address >= pPciDev->Int.s.u8MsiCapOffset)
+        && (u32Address < (unsigned)(pPciDev->Int.s.u8MsiCapOffset + pPciDev->Int.s.u8MsiCapSize))
        )
     {
-        MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
-                          aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
-                          aDev, u32Address, val, len);
+        MsiPciConfigWrite(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
+                          pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
+                          pPciDev, u32Address, val, len);
         return;
     }
 
-    if (   pciDevIsMsixCapable(aDev)
-        && (u32Address >= aDev->Int.s.u8MsixCapOffset)
-        && (u32Address < (unsigned)(aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize))
+    if (   pciDevIsMsixCapable(pPciDev)
+        && (u32Address >= pPciDev->Int.s.u8MsixCapOffset)
+        && (u32Address < (unsigned)(pPciDev->Int.s.u8MsixCapOffset + pPciDev->Int.s.u8MsixCapSize))
        )
     {
-        MsixPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
-                           aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
-                           aDev, u32Address, val, len);
+        MsixPciConfigWrite(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
+                           pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
+                           pPciDev, u32Address, val, len);
         return;
     }
 
     uint32_t addr = u32Address;
     bool     fUpdateMappings = false;
     bool     fP2PBridge = false;
-    /*bool     fPassthrough = pciDevIsPassthrough(aDev);*/
-    uint8_t  u8HeaderType = ich9pciGetByte(aDev, VBOX_PCI_HEADER_TYPE);
+    /*bool     fPassthrough = pciDevIsPassthrough(pPciDev);*/
+    uint8_t  u8HeaderType = ich9pciGetByte(pPciDev, VBOX_PCI_HEADER_TYPE);
 
     for (uint32_t i = 0; i < len; i++)
     {
@@ -2194,7 +2164,7 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Add
                 }
                 break;
             default:
-                AssertMsgFailed(("Unknown header type %x\n", PCIDevGetHeaderType(aDev)));
+                AssertMsgFailed(("Unknown header type %x\n", PCIDevGetHeaderType(pPciDev)));
                 fWritable = false;
                 break;
         }
@@ -2214,13 +2184,13 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Add
                 /* don't change read-only bits => actually all lower bits are read-only */
                 u8Val &= ~UINT32_C(0xff);
                 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
-                aDev->config[addr] &= ~u8Val;
+                pPciDev->abConfig[addr] &= ~u8Val;
                 break;
             case VBOX_PCI_STATUS+1:  /* Status register, bits 8-15. */
                 /* don't change read-only bits */
                 u8Val &= ~UINT32_C(0x06);
                 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
-                aDev->config[addr] &= ~u8Val;
+                pPciDev->abConfig[addr] &= ~u8Val;
                 break;
             case VBOX_PCI_ROM_ADDRESS:    case VBOX_PCI_ROM_ADDRESS   +1: case VBOX_PCI_ROM_ADDRESS   +2: case VBOX_PCI_ROM_ADDRESS   +3:
                 fRom = true;
@@ -2238,7 +2208,7 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Add
                 {
                     int iRegion = fRom ? VBOX_PCI_ROM_SLOT : (addr - VBOX_PCI_BASE_ADDRESS_0) >> 2;
                     int iOffset = addr & 0x3;
-                    ich9pciWriteBarByte(aDev, iRegion, iOffset, u8Val);
+                    ich9pciWriteBarByte(pPciDev, iRegion, iOffset, u8Val);
                     fUpdateMappings = true;
                 }
                 break;
@@ -2246,7 +2216,7 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Add
             default:
             default_case:
                 if (fWritable)
-                    PCIDevSetByte(aDev, addr, u8Val);
+                    PCIDevSetByte(pPciDev, addr, u8Val);
         }
         addr++;
         val >>= 8;
@@ -2254,146 +2224,9 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Add
 
     if (fUpdateMappings)
         /* if the command/base address register is modified, we must modify the mappings */
-        ich9pciUpdateMappings(aDev);
-}
-
-static bool assignPosition(PICH9PCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName, int iDevFn, PciAddress* aPosition)
-{
-    NOREF(pszName);
-    aPosition->iBus = 0;
-    aPosition->iDeviceFunc = iDevFn;
-    aPosition->iRegister = 0; /* N/A */
-
-    /* Explicit slot request */
-    if (iDevFn >= 0 && iDevFn < (int)RT_ELEMENTS(pBus->apDevices))
-        return true;
-
-    int iStartPos = 0;
-
-    /* Otherwise when assigning a slot, we need to make sure all its functions are available */
-    for (int iPos = iStartPos; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
-    {
-        if (        !pBus->apDevices[iPos]
-                &&  !pBus->apDevices[iPos + 1]
-                &&  !pBus->apDevices[iPos + 2]
-                &&  !pBus->apDevices[iPos + 3]
-                &&  !pBus->apDevices[iPos + 4]
-                &&  !pBus->apDevices[iPos + 5]
-                &&  !pBus->apDevices[iPos + 6]
-                &&  !pBus->apDevices[iPos + 7])
-        {
-            pciDevClearRequestedDevfunc(pPciDev);
-            aPosition->iDeviceFunc = iPos;
-            return true;
-        }
-    }
-
-    return false;
+        ich9pciUpdateMappings(pPciDev);
 }
 
-#ifdef SOME_UNUSED_FUNCTION
-static bool hasHardAssignedDevsInSlot(PICH9PCIBUS pBus, int iSlot)
-{
-    PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
-
-    return     (aSlot[0] && pciDevIsRequestedDevfunc(aSlot[0]))
-            || (aSlot[1] && pciDevIsRequestedDevfunc(aSlot[1]))
-            || (aSlot[2] && pciDevIsRequestedDevfunc(aSlot[2]))
-            || (aSlot[3] && pciDevIsRequestedDevfunc(aSlot[3]))
-            || (aSlot[4] && pciDevIsRequestedDevfunc(aSlot[4]))
-            || (aSlot[5] && pciDevIsRequestedDevfunc(aSlot[5]))
-            || (aSlot[6] && pciDevIsRequestedDevfunc(aSlot[6]))
-            || (aSlot[7] && pciDevIsRequestedDevfunc(aSlot[7]))
-           ;
-}
-#endif
-
-static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
-{
-    PciAddress aPosition;
-    aPosition.iBus = 0;
-    aPosition.iDeviceFunc = 0;
-    aPosition.iRegister = 0;
-
-    /*
-     * Find device position
-     */
-    if (!assignPosition(pBus, pPciDev, pszName, iDev, &aPosition))
-    {
-        AssertMsgFailed(("Couldn't asssign position!\n"));
-        return VERR_PDM_TOO_PCI_MANY_DEVICES;
-    }
-
-    AssertMsgReturn(aPosition.iBus == 0,
-                    ("Assigning behind the bridge not implemented yet\n"),
-                    VERR_PDM_TOO_PCI_MANY_DEVICES);
-
-
-    iDev = aPosition.iDeviceFunc;
-    /*
-     * Check if we can really take this slot, possibly by relocating
-     * its current habitant, if it wasn't hard assigned too.
-     */
-    if (pciDevIsRequestedDevfunc(pPciDev) &&
-        pBus->apDevices[iDev]          &&
-        pciDevIsRequestedDevfunc(pBus->apDevices[iDev]))
-    {
-        AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
-                                 pszName, pBus->apDevices[iDev]->name, iDev));
-        return VERR_INTERNAL_ERROR;
-    }
-
-    if (pBus->apDevices[iDev])
-    {
-        /* if we got here, we shall (and usually can) relocate the device */
-        bool assigned = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name, -1, &aPosition);
-        AssertMsgReturn(aPosition.iBus == 0,
-                        ("Assigning behind the bridge not implemented yet\n"),
-                        VERR_PDM_TOO_PCI_MANY_DEVICES);
-        int iRelDev = aPosition.iDeviceFunc;
-        if (!assigned || iRelDev == iDev)
-        {
-            AssertMsgFailed(("Couldn't find free spot!\n"));
-            return VERR_PDM_TOO_PCI_MANY_DEVICES;
-        }
-        /* Copy device function by function to its new position */
-        for (int i = 0; i < 8; i++)
-        {
-            if (!pBus->apDevices[iDev + i])
-                continue;
-            Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
-            pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
-            pBus->apDevices[iRelDev + i]->devfn = iRelDev + i;
-            pBus->apDevices[iDev + i] = NULL;
-        }
-    }
-
-    /*
-     * Fill in device information.
-     */
-    pPciDev->devfn                  = iDev;
-    pPciDev->name                   = pszName;
-    pPciDev->Int.s.pBusR3           = pBus;
-    pPciDev->Int.s.pBusR0           = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
-    pPciDev->Int.s.pBusRC           = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
-    pPciDev->Int.s.pfnConfigRead    = ich9pciConfigReadDev;
-    pPciDev->Int.s.pfnConfigWrite   = ich9pciConfigWriteDev;
-    pBus->apDevices[iDev]           = pPciDev;
-    if (pciDevIsPci2PciBridge(pPciDev))
-    {
-        AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
-        AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
-                  ("device is a bridge but does not implement read/write functions\n"));
-        Log2(("Setting bridge %d on bus %p\n", pBus->cBridges, pBus));
-        pBus->papBridgesR3[pBus->cBridges] = pPciDev;
-        pBus->cBridges++;
-    }
-
-    Log(("PCI: Registered device %d function %d on bus %d (%#x) '%s'.\n",
-         iDev >> 3, iDev & 7, pBus->iBus, 0x80000000 | (iDev << 8), pszName));
-
-    return VINF_SUCCESS;
-}
 
 static void printIndent(PCDBGFINFOHLP pHlp, int iIndent)
 {
@@ -2407,7 +2240,7 @@ static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bo
 {
     for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->apDevices); iDev++)
     {
-        PPCIDEVICE pPciDev = pBus->apDevices[iDev];
+        PPDMPCIDEV pPciDev = pBus->apDevices[iDev];
         if (pPciDev != NULL)
         {
             printIndent(pHlp, iIndent);
@@ -2418,7 +2251,7 @@ static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bo
              */
             pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x",
                             pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
-                            pPciDev->name,
+                            pPciDev->pszNameR3,
                             pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
                             ich9pciGetWord(pPciDev, VBOX_PCI_VENDOR_ID), ich9pciGetWord(pPciDev, VBOX_PCI_DEVICE_ID)
                             );
@@ -2521,7 +2354,7 @@ static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bo
         pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
         for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
         {
-            PICH9PCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PICH9PCIBUS);
+            PICH9PCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns), PICH9PCIBUS);
             ich9pciBusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
         }
     }
@@ -2620,14 +2453,14 @@ static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns, int iInstance, PCF
     pGlobals->aPciBus.pDevInsR3 = pDevIns;
     pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
     pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-    pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
+    pGlobals->aPciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
 
     /*
      * Register bus
      */
     PDMPCIBUSREG PciBusReg;
     PciBusReg.u32Version              = PDM_PCIBUSREG_VERSION;
-    PciBusReg.pfnRegisterR3           = ich9pciRegister;
+    PciBusReg.pfnRegisterR3           = pciR3MergedRegister;
     PciBusReg.pfnRegisterMsiR3        = ich9pciRegisterMsi;
     PciBusReg.pfnIORegionRegisterR3   = ich9pciIORegionRegister;
     PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
@@ -2739,7 +2572,7 @@ static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns, int iInstance, PCF
     return VINF_SUCCESS;
 }
 
-static void ich9pciResetDevice(PPCIDEVICE pDev)
+static void ich9pciResetDevice(PPDMPCIDEV pDev)
 {
     /* Clear regions */
     for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
@@ -2777,14 +2610,14 @@ static void ich9pciResetDevice(PPCIDEVICE pDev)
         if (pciDevIsMsiCapable(pDev))
         {
             /* Extracted from MsiPciConfigWrite(). */
-            pDev->config[pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL] &= 0x8e;
+            pDev->abConfig[pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL] &= 0x8e;
         }
 
         /* Reset MSI-X message control. */
         if (pciDevIsMsixCapable(pDev))
         {
             /* Extracted from MsixPciConfigWrite(); no side effects. */
-            pDev->config[pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL + 1] &= 0x3f;
+            pDev->abConfig[pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL + 1] &= 0x3f;
         }
     }
 }
@@ -2808,13 +2641,13 @@ static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
     for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
     {
         if (pBus->papBridgesR3[iBridge])
-            ich9pcibridgeReset(pBus->papBridgesR3[iBridge]->pDevIns);
+            ich9pcibridgeReset(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns));
     }
 
     ich9pciFakePCIBIOS(pDevIns);
 }
 
-static void ich9pciRelocateDevice(PPCIDEVICE pDev, RTGCINTPTR offDelta)
+static void ich9pciRelocateDevice(PPDMPCIDEV pDev, RTGCINTPTR offDelta)
 {
     if (pDev)
     {
@@ -2879,11 +2712,11 @@ static DECLCALLBACK(int)   ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
     pBus->pDevInsR3 = pDevIns;
     pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
     pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-    pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->apDevices));
+    pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
 
     PDMPCIBUSREG PciBusReg;
     PciBusReg.u32Version              = PDM_PCIBUSREG_VERSION;
-    PciBusReg.pfnRegisterR3           = ich9pcibridgeRegister;
+    PciBusReg.pfnRegisterR3           = pcibridgeR3MergedRegisterDevice;
     PciBusReg.pfnRegisterMsiR3        = ich9pciRegisterMsi;
     PciBusReg.pfnIORegionRegisterR3   = ich9pciIORegionRegister;
     PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
@@ -2927,19 +2760,15 @@ static DECLCALLBACK(int)   ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
      */
     PCIDevSetInterruptPin (&pBus->aPciDev, 0x00);
 
-    pBus->aPciDev.pDevIns                    = pDevIns;
-
-    /* Bridge-specific data */
-    pciDevSetPci2PciBridge(&pBus->aPciDev);
-    pBus->aPciDev.Int.s.pfnBridgeConfigRead  = ich9pcibridgeConfigRead;
-    pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
-
     /*
      * Register this PCI bridge. The called function will take care on which bus we will get registered.
      */
-    rc = PDMDevHlpPCIRegister (pDevIns, &pBus->aPciDev);
+    rc = PDMDevHlpPCIRegisterEx(pDevIns, &pBus->aPciDev, PDMPCIDEVREG_CFG_PRIMARY, PDMPCIDEVREG_F_PCI_BRIDGE,
+                                PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, "ich9pcibridge");
     if (RT_FAILURE(rc))
         return rc;
+    pBus->aPciDev.Int.s.pfnBridgeConfigRead  = ich9pcibridgeConfigRead;
+    pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
 
     /*
      * The iBus property doesn't really represent the bus number
diff --git a/src/VBox/Devices/Bus/DevPciMerge1.cpp.h b/src/VBox/Devices/Bus/DevPciMerge1.cpp.h
new file mode 100644
index 0000000..789b9d4
--- /dev/null
+++ b/src/VBox/Devices/Bus/DevPciMerge1.cpp.h
@@ -0,0 +1,239 @@
+/* $Id: DevPciMerge1.cpp.h $ */
+/** @file
+ * DevPci - Common code that is included by both DevPci and DevPciIch9.
+ *
+ * @note All the code in this file is written by us!
+ * @note No #ifdefs, use instant data booleans/flags/whatever.  Goal is to
+ *       completely merge these files!
+ */
+
+/*
+ * Copyright (C) 2004-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/**
+ * Search for a completely unused device entry (all 8 functions are unused).
+ *
+ * @returns VBox status code.
+ * @param   pBus            The bus to register with.
+ * @remarks Caller enters the PDM critical section.
+ */
+static uint8_t pciR3MergedFindUnusedDeviceNo(PPCIMERGEDBUS pBus)
+{
+    for (uint8_t uPciDevNo = pBus->iDevSearch >> VBOX_PCI_DEVFN_DEV_SHIFT; uPciDevNo < VBOX_PCI_MAX_DEVICES; uPciDevNo++)
+        if (   !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 0)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 1)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 2)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 3)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 4)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 5)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 6)]
+            && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 7)])
+            return uPciDevNo;
+    return UINT8_MAX;
+}
+
+
+
+/**
+ * Registers the device with the specified PCI bus.
+ *
+ * This is shared between the pci bus and pci bridge code.
+ *
+ * @returns VBox status code.
+ * @param   pBus            The bus to register with.
+ * @param   pPciDev         The PCI device structure.
+ * @param   fFlags          Reserved for future use, PDMPCIDEVREG_F_MBZ.
+ * @param   uPciDevNo       PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific
+ *                          device number (0-31).
+ * @param   uPciFunNo       PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific
+ *                          function number (0-7).
+ * @param   pszName         Device name (static but not unique).
+ * @param   pfnConfigRead   The default config read method.
+ * @param   pfnConfigWrite  The default config read method.
+ *
+ * @remarks Caller enters the PDM critical section.
+ */
+static int pciR3MergedRegisterDeviceOnBus(PPCIMERGEDBUS pBus, PPDMPCIDEV pPciDev, uint32_t fFlags,
+                                          uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName,
+                                          PFNPCICONFIGREAD pfnConfigRead, PFNPCICONFIGWRITE pfnConfigWrite)
+{
+    /*
+     * Validate input.
+     */
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrReturn(pPciDev, VERR_INVALID_POINTER);
+    AssertReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK), VERR_INVALID_FLAGS);
+    AssertReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES   || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
+    AssertReturn(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
+
+    /*
+     * Assign device & function numbers.
+     */
+
+    /* Work the optional assignment flag. */
+    if (fFlags & PDMPCIDEVREG_F_NOT_MANDATORY_NO)
+    {
+        AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES && uPciFunNo < VBOX_PCI_MAX_FUNCTIONS,
+                              ("PDMPCIDEVREG_F_NOT_MANDATORY_NO not implemented for #Dev=%#x / #Fun=%#x\n", uPciDevNo, uPciFunNo),
+                              VERR_NOT_IMPLEMENTED);
+        if (pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)])
+        {
+            uPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
+            uPciFunNo = PDMPCIDEVREG_FUN_NO_FIRST_UNUSED;
+        }
+    }
+
+    if (uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED)
+    {
+        /* Just find the next unused device number and we're good. */
+        uPciDevNo = pciR3MergedFindUnusedDeviceNo(pBus);
+        AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES, ("Couldn't find a free spot!\n"), VERR_PDM_TOO_PCI_MANY_DEVICES);
+        if (uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
+            uPciFunNo = 0;
+    }
+    else
+    {
+        /*
+         * Direct assignment of device number can be more complicated.
+         */
+        PPDMPCIDEV pClash;
+        if (uPciFunNo != PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
+        {
+            /* In the case of a specified function, we only relocate an existing
+               device if it belongs to a different device instance.  Reasoning is
+               that the device should figure out it's own function assignments.
+               Note! We could make this more flexible by relocating functions assigned
+                     via PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, but it can wait till it's needed. */
+            pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
+            if (!pClash)
+            { /* likely */ }
+            else if (pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3)
+                AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (same pDevIns)!\n",
+                                             uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
+                                            VERR_PDM_TOO_PCI_MANY_DEVICES);
+            else if (!pClash->Int.s.fReassignableDevNo)
+                AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (different pDevIns)!\n",
+                                             uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
+                                            VERR_PDM_TOO_PCI_MANY_DEVICES);
+        }
+        else
+        {
+            /* First unused function slot.  Again, we only relocate the whole
+               thing if all the device instance differs, because we otherwise
+               reason that a device should manage its own functions correctly. */
+            unsigned cSameDevInses = 0;
+            for (uPciFunNo = 0, pClash = NULL; uPciFunNo < VBOX_PCI_MAX_FUNCTIONS; uPciFunNo++)
+            {
+                pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
+                if (!pClash)
+                    break;
+                cSameDevInses += pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3;
+            }
+            if (!pClash)
+                Assert(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS);
+            else
+                AssertLogRelMsgReturn(cSameDevInses == 0,
+                                      ("PCI Configuration conflict at %u.* appending %s (%u of %u pDevIns matches)!\n",
+                                       uPciDevNo, pszName, cSameDevInses, VBOX_PCI_MAX_FUNCTIONS),
+                                      VERR_PDM_TOO_PCI_MANY_DEVICES);
+        }
+        if (pClash)
+        {
+            /*
+             * Try relocate the existing device.
+             */
+            /* Check that all functions can be moved. */
+            for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
+            {
+                PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
+                AssertLogRelMsgReturn(!pMovePciDev && pMovePciDev->Int.s.fReassignableDevNo,
+                                      ("PCI Configuration conflict at %u.%u: %s vs %s\n",
+                                       uPciDevNo, uMoveFun, pMovePciDev->pszNameR3, pszName),
+                                      VERR_PDM_TOO_PCI_MANY_DEVICES);
+            }
+
+            /* Find a free device number to move it to. */
+            uint8_t uMoveToDevNo = pciR3MergedFindUnusedDeviceNo(pBus);
+            Assert(uMoveToDevNo != uPciFunNo);
+            AssertLogRelMsgReturn(uMoveToDevNo < VBOX_PCI_MAX_DEVICES,
+                                  ("No space to relocate device at %u so '%s' can be placed there instead!\n", uPciFunNo, pszName),
+                                  VERR_PDM_TOO_PCI_MANY_DEVICES);
+
+            /* Execute the move. */
+            for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
+            {
+                PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
+                if (pMovePciDev)
+                {
+                    Log(("PCI: Relocating '%s' from %u.%u to %u.%u.\n", pMovePciDev->pszNameR3, uPciDevNo, uMoveFun, uMoveToDevNo, uMoveFun));
+                    pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)] = NULL;
+                    pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun)] = pMovePciDev;
+                    pMovePciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun);
+                }
+            }
+        }
+    }
+
+    /*
+     * Now, initialize the rest of the PCI device structure.
+     */
+    Assert(!pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]);
+    pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)] = pPciDev;
+
+    pPciDev->uDevFn                 = VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo);
+    pPciDev->Int.s.pBusR3           = pBus;
+    pPciDev->Int.s.pBusR0           = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
+    pPciDev->Int.s.pBusRC           = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
+    pPciDev->Int.s.pfnConfigRead    = pfnConfigRead;
+    pPciDev->Int.s.pfnConfigWrite   = pfnConfigWrite;
+
+    /* Remember and mark bridges. */
+    if (fFlags & PDMPCIDEVREG_F_PCI_BRIDGE)
+    {
+        AssertLogRelMsgReturn(pBus->cBridges < RT_ELEMENTS(pBus->apDevices),
+                              ("Number of bridges exceeds the number of possible devices on the bus\n"),
+                              VERR_INTERNAL_ERROR_3);
+        pBus->papBridgesR3[pBus->cBridges++] = pPciDev;
+        pciDevSetPci2PciBridge(pPciDev);
+    }
+
+    Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
+         uPciDevNo, uPciFunNo, UINT32_C(0x80000000) | (pPciDev->uDevFn << 8), pszName));
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
+ */
+static DECLCALLBACK(int) pciR3MergedRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
+                                             uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
+{
+    PPCIMERGEDBUS pBus = DEVINS_2_PCIBUS(pDevIns);
+    return pciR3MergedRegisterDeviceOnBus(pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName,
+                                          pciR3UnmergedConfigReadDev, pciR3UnmergedConfigWriteDev);
+}
+
+
+/**
+ * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
+ */
+static DECLCALLBACK(int) pcibridgeR3MergedRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
+                                                         uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
+{
+    PPCIMERGEDBUS pBus = PDMINS_2_DATA(pDevIns, PPCIMERGEDBUS);
+    return pciR3MergedRegisterDeviceOnBus(pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName,
+                                          pciR3UnmergedConfigReadDev, pciR3UnmergedConfigWriteDev);
+}
+
diff --git a/src/VBox/Devices/Bus/MsiCommon.cpp b/src/VBox/Devices/Bus/MsiCommon.cpp
index db67fae..2236c01 100644
--- a/src/VBox/Devices/Bus/MsiCommon.cpp
+++ b/src/VBox/Devices/Bus/MsiCommon.cpp
@@ -1,6 +1,8 @@
 /* $Id: MsiCommon.cpp $ */
 /** @file
  * MSI support routines
+ *
+ * @todo Straighten up this file!!
  */
 
 /*
@@ -15,62 +17,62 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
 #define LOG_GROUP LOG_GROUP_DEV_PCI
-/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
-#define PCI_INCLUDE_PRIVATE
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
 #include <VBox/pci.h>
 #include <VBox/msi.h>
 #include <VBox/vmm/pdmdev.h>
 #include <VBox/log.h>
 
 #include "MsiCommon.h"
+#include "PciInline.h"
 
-DECLINLINE(uint16_t) msiGetMessageControl(PPCIDEVICE pDev)
+DECLINLINE(uint16_t) msiGetMessageControl(PPDMPCIDEV pDev)
 {
     uint32_t idxMessageControl = pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL;
 #ifdef IN_RING3
     if (pciDevIsPassthrough(pDev)) {
-        return pDev->Int.s.pfnConfigRead(pDev, idxMessageControl, 2);
+        return pDev->Int.s.pfnConfigRead(pDev->Int.s.CTX_SUFF(pDevIns), pDev, idxMessageControl, 2);
     }
 #endif
     return PCIDevGetWord(pDev, idxMessageControl);
 }
 
-DECLINLINE(bool) msiIs64Bit(PPCIDEVICE pDev)
+DECLINLINE(bool) msiIs64Bit(PPDMPCIDEV pDev)
 {
     return pciDevIsMsi64Capable(pDev);
 }
 
-DECLINLINE(uint32_t*) msiGetMaskBits(PPCIDEVICE pDev)
+DECLINLINE(uint32_t*) msiGetMaskBits(PPDMPCIDEV pDev)
 {
     uint8_t iOff = msiIs64Bit(pDev) ? VBOX_MSI_CAP_MASK_BITS_64 : VBOX_MSI_CAP_MASK_BITS_32;
     /* passthrough devices may have no masked/pending support */
     if (iOff >= pDev->Int.s.u8MsiCapSize)
         return NULL;
     iOff += pDev->Int.s.u8MsiCapOffset;
-    return (uint32_t*)(pDev->config + iOff);
+    return (uint32_t*)(pDev->abConfig + iOff);
 }
 
-DECLINLINE(uint32_t*) msiGetPendingBits(PPCIDEVICE pDev)
+DECLINLINE(uint32_t*) msiGetPendingBits(PPDMPCIDEV pDev)
 {
     uint8_t iOff = msiIs64Bit(pDev) ? VBOX_MSI_CAP_PENDING_BITS_64 : VBOX_MSI_CAP_PENDING_BITS_32;
     /* passthrough devices may have no masked/pending support */
     if (iOff >= pDev->Int.s.u8MsiCapSize)
         return NULL;
     iOff += pDev->Int.s.u8MsiCapOffset;
-    return (uint32_t*)(pDev->config + iOff);
+    return (uint32_t*)(pDev->abConfig + iOff);
 }
 
-DECLINLINE(bool) msiIsEnabled(PPCIDEVICE pDev)
+DECLINLINE(bool) msiIsEnabled(PPDMPCIDEV pDev)
 {
     return (msiGetMessageControl(pDev) & VBOX_PCI_MSI_FLAGS_ENABLE) != 0;
 }
 
-DECLINLINE(uint8_t) msiGetMme(PPCIDEVICE pDev)
+DECLINLINE(uint8_t) msiGetMme(PPDMPCIDEV pDev)
 {
     return (msiGetMessageControl(pDev) & VBOX_PCI_MSI_FLAGS_QSIZE) >> 4;
 }
 
-DECLINLINE(RTGCPHYS) msiGetMsiAddress(PPCIDEVICE pDev)
+DECLINLINE(RTGCPHYS) msiGetMsiAddress(PPDMPCIDEV pDev)
 {
     if (msiIs64Bit(pDev))
     {
@@ -84,7 +86,7 @@ DECLINLINE(RTGCPHYS) msiGetMsiAddress(PPCIDEVICE pDev)
     }
 }
 
-DECLINLINE(uint32_t) msiGetMsiData(PPCIDEVICE pDev, int32_t iVector)
+DECLINLINE(uint32_t) msiGetMsiData(PPDMPCIDEV pDev, int32_t iVector)
 {
     int16_t  iOff = msiIs64Bit(pDev) ? VBOX_MSI_CAP_MESSAGE_DATA_64 : VBOX_MSI_CAP_MESSAGE_DATA_32;
     uint16_t lo = PCIDevGetWord(pDev, pDev->Int.s.u8MsiCapOffset + iOff);
@@ -114,7 +116,7 @@ DECLINLINE(bool) msiBitJustSet(uint32_t uOldValue,
     return (!(uOldValue & uMask) && !!(uNewValue & uMask));
 }
 
-void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev,
+void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev,
                            uint32_t u32Address, uint32_t val, unsigned len)
 {
     int32_t iOff = u32Address - pDev->Int.s.u8MsiCapOffset;
@@ -137,13 +139,13 @@ void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE p
             case VBOX_MSI_CAP_MESSAGE_CONTROL:
                 /* don't change read-only bits: 1-3,7 */
                 u8Val &= UINT8_C(~0x8e);
-                pDev->config[uAddr] = u8Val | (pDev->config[uAddr] & UINT8_C(0x8e));
+                pDev->abConfig[uAddr] = u8Val | (pDev->abConfig[uAddr] & UINT8_C(0x8e));
                 break;
             case VBOX_MSI_CAP_MESSAGE_CONTROL + 1:
                 /* don't change read-only bit 8, and reserved 9-15 */
                 break;
             default:
-                if (pDev->config[uAddr] != u8Val)
+                if (pDev->abConfig[uAddr] != u8Val)
                 {
                     int32_t maskUpdated = -1;
 
@@ -172,26 +174,26 @@ void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE p
                             int32_t iBit = 1 << iBitNum;
                             uint32_t uVector = maskUpdated*8 + iBitNum;
 
-                            if (msiBitJustCleared(pDev->config[uAddr], u8Val, iBit))
+                            if (msiBitJustCleared(pDev->abConfig[uAddr], u8Val, iBit))
                             {
                                 Log(("msi: mask updated bit %d@%x (%d)\n", iBitNum, uAddr, maskUpdated));
 
                                 /* To ensure that we're no longer masked */
-                                pDev->config[uAddr] &= ~iBit;
+                                pDev->abConfig[uAddr] &= ~iBit;
                                 if ((*puPending & (1 << uVector)) != 0)
                                 {
                                     Log(("msi: notify earlier masked pending vector: %d\n", uVector));
                                     MsiNotify(pDevIns, pPciHlp, pDev, uVector, PDM_IRQ_LEVEL_HIGH, 0 /*uTagSrc*/);
                                 }
                             }
-                            if (msiBitJustSet(pDev->config[uAddr], u8Val, iBit))
+                            if (msiBitJustSet(pDev->abConfig[uAddr], u8Val, iBit))
                             {
                                 Log(("msi: mask vector: %d\n", uVector));
                             }
                         }
                     }
 
-                    pDev->config[uAddr] = u8Val;
+                    pDev->abConfig[uAddr] = u8Val;
                 }
         }
         uAddr++;
@@ -199,7 +201,7 @@ void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE p
     }
 }
 
-uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len)
+uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint32_t u32Address, unsigned len)
 {
     RT_NOREF1(pDevIns);
 #if defined(LOG_ENABLED) || defined(VBOX_STRICT)
@@ -228,7 +230,7 @@ uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Addr
     return rv;
 }
 
-int MsiInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
+int MsiInit(PPDMPCIDEV pDev, PPDMMSIREG pMsiReg)
 {
     if (pMsiReg->cMsiVectors == 0)
          return VINF_SUCCESS;
@@ -281,12 +283,12 @@ int MsiInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
 #endif /* IN_RING3 */
 
 
-bool     MsiIsEnabled(PPCIDEVICE pDev)
+bool     MsiIsEnabled(PPDMPCIDEV pDev)
 {
     return pciDevIsMsiCapable(pDev) && msiIsEnabled(pDev);
 }
 
-void MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector, int iLevel, uint32_t uTagSrc)
+void MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, int iVector, int iLevel, uint32_t uTagSrc)
 {
     AssertMsg(msiIsEnabled(pDev), ("Must be enabled to use that"));
 
diff --git a/src/VBox/Devices/Bus/MsiCommon.h b/src/VBox/Devices/Bus/MsiCommon.h
index 38351bf..db652b9 100644
--- a/src/VBox/Devices/Bus/MsiCommon.h
+++ b/src/VBox/Devices/Bus/MsiCommon.h
@@ -29,34 +29,34 @@ typedef PCPDMPCIHLPRC PCPDMPCIHLP;
 
 #ifdef IN_RING3
 /* Init MSI support in the device. */
-int      MsiInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg);
+int      MsiInit(PPDMPCIDEV pDev, PPDMMSIREG pMsiReg);
 #endif
 
 /* If MSI is enabled, so that MSINotify() shall be used for notifications.  */
-bool     MsiIsEnabled(PPCIDEVICE pDev);
+bool     MsiIsEnabled(PPDMPCIDEV pDev);
 
 /* Device notification (aka interrupt). */
-void     MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector, int iLevel, uint32_t uTagSrc);
+void     MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, int iVector, int iLevel, uint32_t uTagSrc);
 
 #ifdef IN_RING3
 /* PCI config space accessors for MSI registers */
-void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len);
-uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len);
+void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, uint32_t u32Address, uint32_t val, unsigned len);
+uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint32_t u32Address, unsigned len);
 #endif
 
 #ifdef IN_RING3
 /* Init MSI-X support in the device. */
-int      MsixInit(PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, PPDMMSIREG pMsiReg);
+int      MsixInit(PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, PPDMMSIREG pMsiReg);
 #endif
 
 /* If MSI-X is enabled, so that MSIXNotify() shall be used for notifications.  */
-bool     MsixIsEnabled(PPCIDEVICE pDev);
+bool     MsixIsEnabled(PPDMPCIDEV pDev);
 
 /* Device notification (aka interrupt). */
-void     MsixNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector, int iLevel, uint32_t uTagSrc);
+void     MsixNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, int iVector, int iLevel, uint32_t uTagSrc);
 
 #ifdef IN_RING3
 /* PCI config space accessors for MSI-X */
-void     MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len);
-uint32_t MsixPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len);
+void     MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, uint32_t u32Address, uint32_t val, unsigned len);
+uint32_t MsixPciConfigRead (PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint32_t u32Address, unsigned len);
 #endif
diff --git a/src/VBox/Devices/Bus/MsixCommon.cpp b/src/VBox/Devices/Bus/MsixCommon.cpp
index e9e5839..517d3a2 100644
--- a/src/VBox/Devices/Bus/MsixCommon.cpp
+++ b/src/VBox/Devices/Bus/MsixCommon.cpp
@@ -15,8 +15,7 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
 #define LOG_GROUP LOG_GROUP_DEV_PCI
-/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
-#define PCI_INCLUDE_PRIVATE
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
 #include <VBox/pci.h>
 #include <VBox/msi.h>
 #include <VBox/vmm/pdmdev.h>
@@ -26,6 +25,7 @@
 #include <iprt/assert.h>
 
 #include "MsiCommon.h"
+#include "PciInline.h"
 
 #pragma pack(1)
 typedef struct
@@ -39,73 +39,73 @@ AssertCompileSize(MsixTableRecord, VBOX_MSIX_ENTRY_SIZE);
 #pragma pack()
 
 /** @todo use accessors so that raw PCI devices work correctly with MSI-X. */
-DECLINLINE(uint16_t)  msixGetMessageControl(PPCIDEVICE pDev)
+DECLINLINE(uint16_t)  msixGetMessageControl(PPDMPCIDEV pDev)
 {
     return PCIDevGetWord(pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL);
 }
 
-DECLINLINE(bool)      msixIsEnabled(PPCIDEVICE pDev)
+DECLINLINE(bool)      msixIsEnabled(PPDMPCIDEV pDev)
 {
     return (msixGetMessageControl(pDev) & VBOX_PCI_MSIX_FLAGS_ENABLE) != 0;
 }
 
-DECLINLINE(bool)      msixIsMasked(PPCIDEVICE pDev)
+DECLINLINE(bool)      msixIsMasked(PPDMPCIDEV pDev)
 {
     return (msixGetMessageControl(pDev) & VBOX_PCI_MSIX_FLAGS_FUNCMASK) != 0;
 }
 
-DECLINLINE(uint16_t)  msixTableSize(PPCIDEVICE pDev)
+DECLINLINE(uint16_t)  msixTableSize(PPDMPCIDEV pDev)
 {
     return (msixGetMessageControl(pDev) & 0x3ff) + 1;
 }
 
-DECLINLINE(uint8_t*)  msixGetPageOffset(PPCIDEVICE pDev, uint32_t off)
+DECLINLINE(uint8_t*)  msixGetPageOffset(PPDMPCIDEV pDev, uint32_t off)
 {
     return (uint8_t*)pDev->Int.s.CTX_SUFF(pMsixPage) + off;
 }
 
-DECLINLINE(MsixTableRecord*) msixGetVectorRecord(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(MsixTableRecord*) msixGetVectorRecord(PPDMPCIDEV pDev, uint32_t iVector)
 {
     return (MsixTableRecord*)msixGetPageOffset(pDev, iVector * VBOX_MSIX_ENTRY_SIZE);
 }
 
-DECLINLINE(RTGCPHYS)  msixGetMsiAddress(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(RTGCPHYS)  msixGetMsiAddress(PPDMPCIDEV pDev, uint32_t iVector)
 {
     MsixTableRecord* pRec = msixGetVectorRecord(pDev, iVector);
     return RT_MAKE_U64(pRec->u32MsgAddressLo & ~UINT32_C(0x3), pRec->u32MsgAddressHi);
 }
 
-DECLINLINE(uint32_t)  msixGetMsiData(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(uint32_t)  msixGetMsiData(PPDMPCIDEV pDev, uint32_t iVector)
 {
     return msixGetVectorRecord(pDev, iVector)->u32MsgData;
 }
 
-DECLINLINE(uint32_t)  msixIsVectorMasked(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(uint32_t)  msixIsVectorMasked(PPDMPCIDEV pDev, uint32_t iVector)
 {
     return (msixGetVectorRecord(pDev, iVector)->u32VectorControl & 0x1) != 0;
 }
 
-DECLINLINE(uint8_t*)  msixPendingByte(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(uint8_t*)  msixPendingByte(PPDMPCIDEV pDev, uint32_t iVector)
 {
     return msixGetPageOffset(pDev, 0x800 + iVector / 8);
 }
 
-DECLINLINE(void)      msixSetPending(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(void)      msixSetPending(PPDMPCIDEV pDev, uint32_t iVector)
 {
     *msixPendingByte(pDev, iVector) |= (1 << (iVector & 0x7));
 }
 
-DECLINLINE(void)      msixClearPending(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(void)      msixClearPending(PPDMPCIDEV pDev, uint32_t iVector)
 {
     *msixPendingByte(pDev, iVector) &= ~(1 << (iVector & 0x7));
 }
 
-DECLINLINE(bool)      msixIsPending(PPCIDEVICE pDev, uint32_t iVector)
+DECLINLINE(bool)      msixIsPending(PPDMPCIDEV pDev, uint32_t iVector)
 {
     return (*msixPendingByte(pDev, iVector) & (1 << (iVector & 0x7))) != 0;
 }
 
-static void msixCheckPendingVector(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t iVector)
+static void msixCheckPendingVector(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, uint32_t iVector)
 {
     if (msixIsPending(pDev, iVector) && !msixIsVectorMasked(pDev, iVector))
         MsixNotify(pDevIns, pPciHlp, pDev, iVector, 1 /* iLevel */, 0 /*uTagSrc*/);
@@ -122,7 +122,7 @@ PDMBOTHCBDECL(int) msixMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
                     VERR_INTERNAL_ERROR);
 
     uint32_t off = (uint32_t)(GCPhysAddr & 0xfff);
-    PPCIDEVICE pPciDev = (PPCIDEVICE)pvUser;
+    PPDMPCIDEV pPciDev = (PPDMPCIDEV)pvUser;
 
     *(uint32_t*)pv = *(uint32_t*)msixGetPageOffset(pPciDev, off);
 
@@ -135,7 +135,7 @@ PDMBOTHCBDECL(int) msixMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPh
     AssertMsgReturn(cb == 4,
                     ("MSI-X must be accessed with 4-byte reads"),
                     VERR_INTERNAL_ERROR);
-    PPCIDEVICE pPciDev = (PPCIDEVICE)pvUser;
+    PPDMPCIDEV pPciDev = (PPDMPCIDEV)pvUser;
 
     uint32_t off = (uint32_t)(GCPhysAddr & 0xfff);
 
@@ -151,12 +151,13 @@ PDMBOTHCBDECL(int) msixMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPh
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) msixMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) msixMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     Assert(enmType == PCI_ADDRESS_SPACE_MEM);
     NOREF(iRegion); NOREF(enmType);
 
-    int rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pPciDev,
+    int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, pPciDev,
                                    IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
                                    msixMMIOWrite, msixMMIORead, "MSI-X tables");
 
@@ -166,7 +167,7 @@ static DECLCALLBACK(int) msixMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhy
     return VINF_SUCCESS;
 }
 
-int MsixInit(PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
+int MsixInit(PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, PPDMMSIREG pMsiReg)
 {
     if (pMsiReg->cMsixVectors == 0)
          return VINF_SUCCESS;
@@ -198,14 +199,14 @@ int MsixInit(PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
     /* If device is passthrough, BAR is registered using common mechanism. */
     if (!pciDevIsPassthrough(pDev))
     {
-        rc = PDMDevHlpPCIIORegionRegister(pDev->pDevIns, iBar, 0x1000, PCI_ADDRESS_SPACE_MEM, msixMap);
+        rc = PDMDevHlpPCIIORegionRegister(pDev->Int.s.CTX_SUFF(pDevIns), iBar, 0x1000, PCI_ADDRESS_SPACE_MEM, msixMap);
         if (RT_FAILURE (rc))
             return rc;
     }
 
     pDev->Int.s.u8MsixCapOffset = iCapOffset;
     pDev->Int.s.u8MsixCapSize   = VBOX_MSIX_CAP_SIZE;
-    PVM pVM = PDMDevHlpGetVM(pDev->pDevIns);
+    PVM pVM = PDMDevHlpGetVM(pDev->Int.s.CTX_SUFF(pDevIns));
 
     pDev->Int.s.pMsixPageR3     = NULL;
 
@@ -234,12 +235,12 @@ int MsixInit(PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
 }
 #endif
 
-bool     MsixIsEnabled(PPCIDEVICE pDev)
+bool     MsixIsEnabled(PPDMPCIDEV pDev)
 {
     return pciDevIsMsixCapable(pDev) && msixIsEnabled(pDev);
 }
 
-void MsixNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector, int iLevel, uint32_t uTagSrc)
+void MsixNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, int iVector, int iLevel, uint32_t uTagSrc)
 {
     AssertMsg(msixIsEnabled(pDev), ("Must be enabled to use that"));
 
@@ -275,14 +276,14 @@ DECLINLINE(bool) msixBitJustCleared(uint32_t uOldValue,
     return (!!(uOldValue & uMask) && !(uNewValue & uMask));
 }
 
-static void msixCheckPendingVectors(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev)
+static void msixCheckPendingVectors(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev)
 {
     for (uint32_t i = 0; i < msixTableSize(pDev); i++)
         msixCheckPendingVector(pDevIns, pPciHlp, pDev, i);
 }
 
 
-void MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len)
+void MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPDMPCIDEV pDev, uint32_t u32Address, uint32_t val, unsigned len)
 {
     int32_t iOff = u32Address - pDev->Int.s.u8MsixCapOffset;
     Assert(iOff >= 0 && (pciDevIsMsixCapable(pDev) && iOff < pDev->Int.s.u8MsixCapSize));
@@ -308,11 +309,11 @@ void MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev
             case VBOX_MSIX_CAP_MESSAGE_CONTROL + 1:
             {
                 /* don't change read-only bits 8-13 */
-                u8NewVal = (u8Val & UINT8_C(~0x3f)) | (pDev->config[uAddr] & UINT8_C(0x3f));
+                u8NewVal = (u8Val & UINT8_C(~0x3f)) | (pDev->abConfig[uAddr] & UINT8_C(0x3f));
                 /* If just enabled globally - check pending vectors */
-                fJustEnabled |= msixBitJustCleared(pDev->config[uAddr], u8NewVal, VBOX_PCI_MSIX_FLAGS_ENABLE >> 8);
-                fJustEnabled |= msixBitJustCleared(pDev->config[uAddr], u8NewVal, VBOX_PCI_MSIX_FLAGS_FUNCMASK >> 8);
-                pDev->config[uAddr] = u8NewVal;
+                fJustEnabled |= msixBitJustCleared(pDev->abConfig[uAddr], u8NewVal, VBOX_PCI_MSIX_FLAGS_ENABLE >> 8);
+                fJustEnabled |= msixBitJustCleared(pDev->abConfig[uAddr], u8NewVal, VBOX_PCI_MSIX_FLAGS_FUNCMASK >> 8);
+                pDev->abConfig[uAddr] = u8NewVal;
                 break;
         }
             default:
@@ -328,7 +329,7 @@ void MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev
 }
 
 
-uint32_t MsixPciConfigRead(PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len)
+uint32_t MsixPciConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint32_t u32Address, unsigned len)
 {
     NOREF(pDevIns);
 #if defined(LOG_ENABLED) || defined(VBOX_STRICT)
diff --git a/src/VBox/Devices/Bus/PciInline.h b/src/VBox/Devices/Bus/PciInline.h
new file mode 100644
index 0000000..abf6f64
--- /dev/null
+++ b/src/VBox/Devices/Bus/PciInline.h
@@ -0,0 +1,101 @@
+/** @file
+ * PCI - The PCI Controller And Devices, inline device helpers.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___Bus_PciInline_h
+#define ___Bus_PciInline_h
+
+DECLINLINE(void) pciDevSetPci2PciBridge(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags |= PCIDEV_FLAG_PCI_TO_PCI_BRIDGE;
+}
+
+DECLINLINE(bool) pciDevIsPci2PciBridge(PPDMPCIDEV pDev)
+{
+    return (pDev->Int.s.fFlags & PCIDEV_FLAG_PCI_TO_PCI_BRIDGE) != 0;
+}
+
+DECLINLINE(void) pciDevSetPciExpress(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags |= PCIDEV_FLAG_PCI_EXPRESS_DEVICE;
+}
+
+DECLINLINE(bool) pciDevIsPciExpress(PPDMPCIDEV pDev)
+{
+    return (pDev->Int.s.fFlags & PCIDEV_FLAG_PCI_EXPRESS_DEVICE) != 0;
+}
+
+DECLINLINE(void) pciDevSetMsiCapable(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags |= PCIDEV_FLAG_MSI_CAPABLE;
+}
+
+DECLINLINE(void) pciDevClearMsiCapable(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_MSI_CAPABLE;
+}
+
+DECLINLINE(bool) pciDevIsMsiCapable(PPDMPCIDEV pDev)
+{
+    return (pDev->Int.s.fFlags & PCIDEV_FLAG_MSI_CAPABLE) != 0;
+}
+
+DECLINLINE(void) pciDevSetMsi64Capable(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags |= PCIDEV_FLAG_MSI64_CAPABLE;
+}
+
+DECLINLINE(void) pciDevClearMsi64Capable(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_MSI64_CAPABLE;
+}
+
+DECLINLINE(bool) pciDevIsMsi64Capable(PPDMPCIDEV pDev)
+{
+    return (pDev->Int.s.fFlags & PCIDEV_FLAG_MSI64_CAPABLE) != 0;
+}
+
+DECLINLINE(void) pciDevSetMsixCapable(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags |= PCIDEV_FLAG_MSIX_CAPABLE;
+}
+
+DECLINLINE(void) pciDevClearMsixCapable(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_MSIX_CAPABLE;
+}
+
+DECLINLINE(bool) pciDevIsMsixCapable(PPDMPCIDEV pDev)
+{
+    return (pDev->Int.s.fFlags & PCIDEV_FLAG_MSIX_CAPABLE) != 0;
+}
+
+DECLINLINE(void) pciDevSetPassthrough(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags |= PCIDEV_FLAG_PASSTHROUGH;
+}
+
+DECLINLINE(void) pciDevClearPassthrough(PPDMPCIDEV pDev)
+{
+    pDev->Int.s.fFlags &= ~PCIDEV_FLAG_PASSTHROUGH;
+}
+
+DECLINLINE(bool) pciDevIsPassthrough(PPDMPCIDEV pDev)
+{
+    return (pDev->Int.s.fFlags & PCIDEV_FLAG_PASSTHROUGH) != 0;
+}
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd
index 6c31ddd..49203ff 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd differ
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd
index 95b0b74..ca5641a 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd differ
diff --git a/src/VBox/Devices/GIMDev/GIMDev.cpp b/src/VBox/Devices/GIMDev/GIMDev.cpp
index 295e9a1..cc5956f 100644
--- a/src/VBox/Devices/GIMDev/GIMDev.cpp
+++ b/src/VBox/Devices/GIMDev/GIMDev.cpp
@@ -284,8 +284,8 @@ static DECLCALLBACK(int) gimdevR3Construct(PPDMDEVINS pDevIns, int iInstance, PC
         for (uint32_t i = 0; i < cRegions; i++, pCur++)
         {
             Assert(!pCur->fRegistered);
-            rc = PDMDevHlpMMIO2Register(pDevIns, pCur->iRegion, pCur->cbRegion, 0 /* fFlags */, &pCur->pvPageR3,
-                                            pCur->szDescription);
+            rc = PDMDevHlpMMIO2Register(pDevIns, NULL, pCur->iRegion, pCur->cbRegion, 0 /* fFlags */, &pCur->pvPageR3,
+                                        pCur->szDescription);
             if (RT_FAILURE(rc))
                 return rc;
 
@@ -293,7 +293,7 @@ static DECLCALLBACK(int) gimdevR3Construct(PPDMDEVINS pDevIns, int iInstance, PC
 
 #if defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
             RTR0PTR pR0Mapping = 0;
-            rc = PDMDevHlpMMIO2MapKernel(pDevIns, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription,
+            rc = PDMDevHlpMMIO2MapKernel(pDevIns, NULL, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription,
                                          &pR0Mapping);
             AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMapMMIO2IntoR0(%#x,) -> %Rrc\n", pCur->cbRegion, rc), rc);
             pCur->pvPageR0 = pR0Mapping;
@@ -307,7 +307,7 @@ static DECLCALLBACK(int) gimdevR3Construct(PPDMDEVINS pDevIns, int iInstance, PC
             if (pCur->fRCMapping)
             {
                 RTRCPTR pRCMapping = 0;
-                rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription,
+                rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, NULL, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription,
                                               &pRCMapping);
                 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", pCur->cbRegion, rc), rc);
                 pCur->pvPageRC = pRCMapping;
@@ -339,7 +339,7 @@ static DECLCALLBACK(int) gimdevR3Destruct(PPDMDEVINS pDevIns)
     PGIMMMIO2REGION pCur = GIMR3GetMmio2Regions(pVM, &cRegions);
     for (uint32_t i = 0; i < cRegions; i++, pCur++)
     {
-        int rc = PDMDevHlpMMIO2Deregister(pDevIns, pCur->iRegion);
+        int rc = PDMDevHlpMMIOExDeregister(pDevIns, NULL, pCur->iRegion);
         if (RT_FAILURE(rc))
             return rc;
     }
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
index 74d2093..9771ea3 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
@@ -1669,7 +1669,7 @@ vga_read_char_attr_:                         ; 0xc0ad1 LB 0xb0
     mov bl, byte [bp-00ch]                    ; 8a 5e f4
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 00b68h                          ; 75 2c
     mul di                                    ; f7 e7
     add ax, ax                                ; 01 c0
@@ -1687,7 +1687,7 @@ vga_read_char_attr_:                         ; 0xc0ad1 LB 0xb0
     add dx, ax                                ; 01 c2
     add dx, dx                                ; 01 d2
     add dx, di                                ; 01 fa
-    mov ax, word [bx+04632h]                  ; 8b 87 32 46
+    mov ax, word [bx+04633h]                  ; 8b 87 33 46
     call 03181h                               ; e8 1c 26
     mov word [ss:si], ax                      ; 36 89 04
     lea sp, [bp-008h]                         ; 8d 66 f8
@@ -1754,18 +1754,18 @@ vga_get_font_info_:                          ; 0xc0b81 LB 0x7b
     retn 00002h                               ; c2 02 00
     mov dx, 0010ch                            ; ba 0c 01
     jmp short 00b99h                          ; eb c0
-    mov ax, 05bech                            ; b8 ec 5b
+    mov ax, 05bedh                            ; b8 ed 5b
     mov dx, 0c000h                            ; ba 00 c0
     jmp short 00b9eh                          ; eb bd
-    mov ax, 053ech                            ; b8 ec 53
+    mov ax, 053edh                            ; b8 ed 53
     jmp short 00bdch                          ; eb f6
-    mov ax, 057ech                            ; b8 ec 57
+    mov ax, 057edh                            ; b8 ed 57
     jmp short 00bdch                          ; eb f1
-    mov ax, 079ech                            ; b8 ec 79
+    mov ax, 079edh                            ; b8 ed 79
     jmp short 00bdch                          ; eb ec
-    mov ax, 069ech                            ; b8 ec 69
+    mov ax, 069edh                            ; b8 ed 69
     jmp short 00bdch                          ; eb e7
-    mov ax, 07b19h                            ; b8 19 7b
+    mov ax, 07b1ah                            ; b8 1a 7b
     jmp short 00bdch                          ; eb e2
     jmp short 00bcbh                          ; eb cf
 vga_read_pixel_:                             ; 0xc0bfc LB 0x142
@@ -1788,10 +1788,10 @@ vga_read_pixel_:                             ; 0xc0bfc LB 0x142
     mov bl, al                                ; 88 c3
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 00c30h                          ; 75 03
     jmp near 00d37h                           ; e9 07 01
-    mov bl, byte [bx+04630h]                  ; 8a 9f 30 46
+    mov bl, byte [bx+04631h]                  ; 8a 9f 31 46
     cmp bl, 003h                              ; 80 fb 03
     jc short 00c48h                           ; 72 0f
     jbe short 00c50h                          ; 76 15
@@ -1856,7 +1856,7 @@ vga_read_pixel_:                             ; 0xc0bfc LB 0x142
     mov bl, cl                                ; 88 cb
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+04631h], 002h                ; 80 bf 31 46 02
+    cmp byte [bx+04632h], 002h                ; 80 bf 32 46 02
     jne short 00cf8h                          ; 75 1b
     mov cx, si                                ; 89 f1
     xor ch, ch                                ; 30 ed
@@ -2180,7 +2180,7 @@ biosfn_set_active_page_:                     ; 0xc0f2e LB 0xee
     xor bh, bh                                ; 30 ff
     mov si, bx                                ; 89 de
     sal si, 003h                              ; c1 e6 03
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 00fbah                          ; 75 46
     mov dx, strict word 0004ah                ; ba 4a 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2213,14 +2213,14 @@ biosfn_set_active_page_:                     ; 0xc0f2e LB 0xee
     inc ax                                    ; 40
     mul si                                    ; f7 e6
     jmp short 00fd0h                          ; eb 16
-    mov al, byte [bx+046aeh]                  ; 8a 87 ae 46
+    mov al, byte [bx+046afh]                  ; 8a 87 af 46
     xor ah, ah                                ; 30 e4
     mov bx, ax                                ; 89 c3
     sal bx, 006h                              ; c1 e3 06
     mov cl, byte [bp-00ah]                    ; 8a 4e f6
     xor ch, ch                                ; 30 ed
     mov ax, cx                                ; 89 c8
-    mul word [bx+046c5h]                      ; f7 a7 c5 46
+    mul word [bx+046c6h]                      ; f7 a7 c6 46
     mov bx, ax                                ; 89 c3
     mov dx, strict word 00063h                ; ba 63 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2294,17 +2294,17 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov byte [bp-01ah], al                    ; 88 46 e6
     mov byte [bp-019h], 000h                  ; c6 46 e7 00
     mov bx, word [bp-01ah]                    ; 8b 5e e6
-    mov al, byte [bx+046aeh]                  ; 8a 87 ae 46
+    mov al, byte [bx+046afh]                  ; 8a 87 af 46
     mov byte [bp-00eh], al                    ; 88 46 f2
     mov bl, al                                ; 88 c3
     xor bh, bh                                ; 30 ff
     sal bx, 006h                              ; c1 e3 06
-    mov al, byte [bx+046c2h]                  ; 8a 87 c2 46
+    mov al, byte [bx+046c3h]                  ; 8a 87 c3 46
     xor ah, ah                                ; 30 e4
     mov word [bp-016h], ax                    ; 89 46 ea
-    mov al, byte [bx+046c3h]                  ; 8a 87 c3 46
-    mov word [bp-014h], ax                    ; 89 46 ec
     mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
+    mov word [bp-014h], ax                    ; 89 46 ec
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
     mov word [bp-018h], ax                    ; 89 46 e8
     mov dx, 00087h                            ; ba 87 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2320,13 +2320,13 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     jne short 010f7h                          ; 75 45
     mov bx, word [bp-01ah]                    ; 8b 5e e6
     sal bx, 003h                              ; c1 e3 03
-    mov al, byte [bx+04634h]                  ; 8a 87 34 46
+    mov al, byte [bx+04635h]                  ; 8a 87 35 46
     mov dx, 003c6h                            ; ba c6 03
     out DX, AL                                ; ee
     xor al, al                                ; 30 c0
     mov dx, 003c8h                            ; ba c8 03
     out DX, AL                                ; ee
-    mov bl, byte [bx+04635h]                  ; 8a 9f 35 46
+    mov bl, byte [bx+04636h]                  ; 8a 9f 36 46
     cmp bl, 001h                              ; 80 fb 01
     jc short 010ddh                           ; 72 0e
     jbe short 010e6h                          ; 76 15
@@ -2337,13 +2337,13 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     jmp short 010f3h                          ; eb 16
     test bl, bl                               ; 84 db
     jne short 010f3h                          ; 75 12
-    mov di, 04e42h                            ; bf 42 4e
+    mov di, 04e43h                            ; bf 43 4e
     jmp short 010f3h                          ; eb 0d
-    mov di, 04f02h                            ; bf 02 4f
+    mov di, 04f03h                            ; bf 03 4f
     jmp short 010f3h                          ; eb 08
-    mov di, 04fc2h                            ; bf c2 4f
+    mov di, 04fc3h                            ; bf c3 4f
     jmp short 010f3h                          ; eb 03
-    mov di, 05082h                            ; bf 82 50
+    mov di, 05083h                            ; bf 83 50
     xor bx, bx                                ; 31 db
     jmp short 010ffh                          ; eb 08
     jmp short 01144h                          ; eb 4b
@@ -2353,9 +2353,9 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     xor ah, ah                                ; 30 e4
     mov si, ax                                ; 89 c6
     sal si, 003h                              ; c1 e6 03
-    mov al, byte [si+04635h]                  ; 8a 84 35 46
+    mov al, byte [si+04636h]                  ; 8a 84 36 46
     mov si, ax                                ; 89 c6
-    mov al, byte [si+046beh]                  ; 8a 84 be 46
+    mov al, byte [si+046bfh]                  ; 8a 84 bf 46
     cmp bx, ax                                ; 39 c3
     jnbe short 0112ch                         ; 77 15
     imul si, bx, strict byte 00003h           ; 6b f3 03
@@ -2396,7 +2396,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov si, ax                                ; 89 c6
     sal si, 006h                              ; c1 e6 06
     add si, bx                                ; 01 de
-    mov al, byte [si+046e5h]                  ; 8a 84 e5 46
+    mov al, byte [si+046e6h]                  ; 8a 84 e6 46
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 0114eh                          ; eb e1
@@ -2422,7 +2422,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov si, ax                                ; 89 c6
     sal si, 006h                              ; c1 e6 06
     add si, bx                                ; 01 de
-    mov al, byte [si+046c6h]                  ; 8a 84 c6 46
+    mov al, byte [si+046c7h]                  ; 8a 84 c7 46
     mov dx, 003c5h                            ; ba c5 03
     out DX, AL                                ; ee
     inc bx                                    ; 43
@@ -2439,7 +2439,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov si, ax                                ; 89 c6
     sal si, 006h                              ; c1 e6 06
     add si, bx                                ; 01 de
-    mov al, byte [si+046f9h]                  ; 8a 84 f9 46
+    mov al, byte [si+046fah]                  ; 8a 84 fa 46
     mov dx, 003cfh                            ; ba cf 03
     out DX, AL                                ; ee
     inc bx                                    ; 43
@@ -2447,7 +2447,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov bl, byte [bp-010h]                    ; 8a 5e f0
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+04630h], 001h                ; 80 bf 30 46 01
+    cmp byte [bx+04631h], 001h                ; 80 bf 31 46 01
     jne short 011e1h                          ; 75 05
     mov dx, 003b4h                            ; ba b4 03
     jmp short 011e4h                          ; eb 03
@@ -2469,12 +2469,12 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov di, cx                                ; 89 cf
     add di, bx                                ; 01 df
     lea dx, [si+001h]                         ; 8d 54 01
-    mov al, byte [di+046cch]                  ; 8a 85 cc 46
+    mov al, byte [di+046cdh]                  ; 8a 85 cd 46
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 011eeh                          ; eb dd
     mov bx, cx                                ; 89 cb
-    mov al, byte [bx+046cbh]                  ; 8a 87 cb 46
+    mov al, byte [bx+046cch]                  ; 8a 87 cc 46
     mov dx, 003c2h                            ; ba c2 03
     out DX, AL                                ; ee
     mov AL, strict byte 020h                  ; b0 20
@@ -2489,9 +2489,9 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov bl, byte [bp-010h]                    ; 8a 5e f0
     xor bh, ch                                ; 30 ef
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 0124fh                          ; 75 13
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 04000h                            ; b9 00 40
     mov ax, 00720h                            ; b8 20 07
     xor di, di                                ; 31 ff
@@ -2501,7 +2501,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     jmp short 0128dh                          ; eb 3e
     cmp byte [bp-00ch], 00dh                  ; 80 7e f4 0d
     jnc short 01267h                          ; 73 12
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 04000h                            ; b9 00 40
     xor ax, ax                                ; 31 c0
     xor di, di                                ; 31 ff
@@ -2519,7 +2519,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov word [bp-01ch], ax                    ; 89 46 e4
     mov AL, strict byte 00fh                  ; b0 0f
     out DX, AL                                ; ee
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 08000h                            ; b9 00 80
     xor ax, ax                                ; 31 c0
     xor di, di                                ; 31 ff
@@ -2540,7 +2540,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov bl, byte [bp-00eh]                    ; 8a 5e f2
     xor bh, bh                                ; 30 ff
     sal bx, 006h                              ; c1 e3 06
-    mov bx, word [bx+046c5h]                  ; 8b 9f c5 46
+    mov bx, word [bx+046c6h]                  ; 8b 9f c6 46
     mov dx, strict word 0004ch                ; ba 4c 00
     mov ax, strict word 00040h                ; b8 40 00
     call 0318fh                               ; e8 d3 1e
@@ -2581,7 +2581,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov ax, strict word 00040h                ; b8 40 00
     call 03173h                               ; e8 50 1e
     mov cx, ds                                ; 8c d9
-    mov bx, 053d0h                            ; bb d0 53
+    mov bx, 053d1h                            ; bb d1 53
     mov dx, 000a8h                            ; ba a8 00
     mov ax, strict word 00040h                ; b8 40 00
     call 031afh                               ; e8 7e 1e
@@ -2596,7 +2596,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov bl, byte [bp-010h]                    ; 8a 5e f0
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 0135fh                          ; 75 09
     mov dx, strict word 00007h                ; ba 07 00
     mov ax, strict word 00006h                ; b8 06 00
@@ -2616,7 +2616,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov bl, byte [bp-010h]                    ; 8a 5e f0
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 01398h                          ; 75 10
     xor bl, bl                                ; 30 db
     mov AL, strict byte 004h                  ; b0 04
@@ -2626,7 +2626,7 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     mov AL, strict byte 003h                  ; b0 03
     mov AH, strict byte 011h                  ; b4 11
     int 010h                                  ; cd 10
-    mov dx, 057ech                            ; ba ec 57
+    mov dx, 057edh                            ; ba ed 57
     mov ax, strict word 0001fh                ; b8 1f 00
     call 00a00h                               ; e8 5f f6
     mov ax, word [bp-018h]                    ; 8b 46 e8
@@ -2636,13 +2636,13 @@ biosfn_set_video_mode_:                      ; 0xc101c LB 0x3b6
     je short 013beh                           ; 74 10
     cmp ax, strict word 00008h                ; 3d 08 00
     jne short 013c8h                          ; 75 15
-    mov dx, 053ech                            ; ba ec 53
+    mov dx, 053edh                            ; ba ed 53
     mov ax, strict word 00043h                ; b8 43 00
     call 00a00h                               ; e8 44 f6
     jmp short 013c8h                          ; eb 0a
-    mov dx, 05bech                            ; ba ec 5b
+    mov dx, 05bedh                            ; ba ed 5b
     jmp short 013b6h                          ; eb f3
-    mov dx, 069ech                            ; ba ec 69
+    mov dx, 069edh                            ; ba ed 69
     jmp short 013b6h                          ; eb ee
     lea sp, [bp-00ah]                         ; 8d 66 f6
     pop di                                    ; 5f
@@ -3030,7 +3030,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     mov ax, word [bp-018h]                    ; 8b 46 e8
     mul cx                                    ; f7 e1
     mov si, ax                                ; 89 c6
-    cmp byte [di+0462fh], 000h                ; 80 bd 2f 46 00
+    cmp byte [di+04630h], 000h                ; 80 bd 30 46 00
     jne short 01758h                          ; 75 51
     add ax, ax                                ; 01 c0
     or AL, strict byte 0ffh                   ; 0c ff
@@ -3058,7 +3058,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     mov al, byte [bp-010h]                    ; 8a 46 f0
     sal ax, 008h                              ; c1 e0 08
     add ax, strict word 00020h                ; 05 20 00
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, si                                ; 89 f1
     mov di, bx                                ; 89 df
     cld                                       ; fc
@@ -3102,7 +3102,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     xor ah, ah                                ; 30 e4
     mov si, ax                                ; 89 c6
     sal si, 003h                              ; c1 e6 03
-    mov es, [si+04632h]                       ; 8e 84 32 46
+    mov es, [si+04633h]                       ; 8e 84 33 46
     mov ax, word [bp-01eh]                    ; 8b 46 e2
     cld                                       ; fc
     jcxz 017c3h                               ; e3 02
@@ -3123,7 +3123,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     mov al, byte [bp-00ch]                    ; 8a 46 f4
     mov si, ax                                ; 89 c6
     sal si, 003h                              ; c1 e6 03
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov word [bp-01eh], ax                    ; 89 46 e2
     mov ax, word [bp-016h]                    ; 8b 46 ea
     mul word [bp-018h]                        ; f7 66 e8
@@ -3174,7 +3174,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     mov al, byte [bp-00ch]                    ; 8a 46 f4
     mov si, ax                                ; 89 c6
     sal si, 003h                              ; c1 e6 03
-    mov es, [si+04632h]                       ; 8e 84 32 46
+    mov es, [si+04633h]                       ; 8e 84 33 46
     mov ax, word [bp-01eh]                    ; 8b 46 e2
     cld                                       ; fc
     jcxz 01872h                               ; e3 02
@@ -3197,7 +3197,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     mov al, byte [bp-00ch]                    ; 8a 46 f4
     mov si, ax                                ; 89 c6
     sal si, 003h                              ; c1 e6 03
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov word [bp-014h], ax                    ; 89 46 ec
     mov ax, word [bp-016h]                    ; 8b 46 ea
     mul word [bp-018h]                        ; f7 66 e8
@@ -3221,13 +3221,13 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     jc short 018fbh                           ; 72 2b
     dec word [bp-016h]                        ; ff 4e ea
     jmp near 0181ch                           ; e9 46 ff
-    mov al, byte [bx+046aeh]                  ; 8a 87 ae 46
+    mov al, byte [bx+046afh]                  ; 8a 87 af 46
     xor ah, ah                                ; 30 e4
     mov bx, ax                                ; 89 c3
     sal bx, 006h                              ; c1 e3 06
-    mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
     mov byte [bp-012h], al                    ; 88 46 ee
-    mov bl, byte [di+04630h]                  ; 8a 9d 30 46
+    mov bl, byte [di+04631h]                  ; 8a 9d 31 46
     cmp bl, 004h                              ; 80 fb 04
     je short 018feh                           ; 74 0d
     cmp bl, 003h                              ; 80 fb 03
@@ -3271,7 +3271,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     xor dh, dh                                ; 30 f6
     mov bx, dx                                ; 89 d3
     sal bx, 003h                              ; c1 e3 03
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     xor di, di                                ; 31 ff
     cld                                       ; fc
     jcxz 0195fh                               ; e3 02
@@ -3379,7 +3379,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     jc short 01aa2h                           ; 72 4a
     dec word [bp-016h]                        ; ff 4e ea
     jmp short 019efh                          ; eb 92
-    mov bl, byte [di+04631h]                  ; 8a 9d 31 46
+    mov bl, byte [di+04632h]                  ; 8a 9d 32 46
     cmp byte [bp-006h], 000h                  ; 80 7e fa 00
     jne short 01aa5h                          ; 75 3e
     cmp byte [bp-00ah], 000h                  ; 80 7e f6 00
@@ -3399,7 +3399,7 @@ biosfn_scroll_:                              ; 0xc1647 LB 0x55a
     xor bh, bh                                ; 30 ff
     mul bx                                    ; f7 e3
     mov bl, byte [bp-010h]                    ; 8a 5e f0
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, ax                                ; 89 c1
     mov ax, bx                                ; 89 d8
     xor di, di                                ; 31 ff
@@ -3524,11 +3524,11 @@ write_gfx_char_pl4_:                         ; 0xc1ba1 LB 0xfb
     je short 01bc5h                           ; 74 0b
     cmp byte [bp+006h], 00eh                  ; 80 7e 06 0e
     jne short 01bcah                          ; 75 0a
-    mov di, 05bech                            ; bf ec 5b
+    mov di, 05bedh                            ; bf ed 5b
     jmp short 01bcdh                          ; eb 08
-    mov di, 069ech                            ; bf ec 69
+    mov di, 069edh                            ; bf ed 69
     jmp short 01bcdh                          ; eb 03
-    mov di, 053ech                            ; bf ec 53
+    mov di, 053edh                            ; bf ed 53
     xor ah, ah                                ; 30 e4
     mov bx, ax                                ; 89 c3
     mov al, byte [bp+006h]                    ; 8a 46 06
@@ -3628,7 +3628,7 @@ write_gfx_char_cga_:                         ; 0xc1c9c LB 0x138
     mov byte [bp-00ah], al                    ; 88 46 f6
     mov byte [bp-008h], dl                    ; 88 56 f8
     mov al, bl                                ; 88 d8
-    mov si, 053ech                            ; be ec 53
+    mov si, 053edh                            ; be ed 53
     xor ah, ah                                ; 30 e4
     mov bx, ax                                ; 89 c3
     mov al, byte [bp+006h]                    ; 8a 46 06
@@ -3763,7 +3763,7 @@ write_gfx_char_lin_:                         ; 0xc1dd4 LB 0xaa
     mov byte [bp-00ch], dl                    ; 88 56 f4
     mov byte [bp-006h], bl                    ; 88 5e fa
     mov al, cl                                ; 88 c8
-    mov si, 053ech                            ; be ec 53
+    mov si, 053edh                            ; be ed 53
     xor ah, ah                                ; 30 e4
     mov bl, byte [bp+004h]                    ; 8a 5e 04
     xor bh, bh                                ; 30 ff
@@ -3876,7 +3876,7 @@ biosfn_write_char_attr_:                     ; 0xc1e7e LB 0x18d
     xor ah, ah                                ; 30 e4
     mov di, ax                                ; 89 c7
     sal di, 003h                              ; c1 e7 03
-    cmp byte [di+0462fh], 000h                ; 80 bd 2f 46 00
+    cmp byte [di+04630h], 000h                ; 80 bd 30 46 00
     jne short 01f49h                          ; 75 52
     mov ax, bx                                ; 89 d8
     mul word [bp-018h]                        ; f7 66 e8
@@ -3907,7 +3907,7 @@ biosfn_write_char_attr_:                     ; 0xc1e7e LB 0x18d
     add bx, ax                                ; 01 c3
     mov word [bp-01ah], bx                    ; 89 5e e6
     mov ax, word [bp-01ah]                    ; 8b 46 e6
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, si                                ; 89 f1
     mov di, dx                                ; 89 d7
     cld                                       ; fc
@@ -3915,12 +3915,12 @@ biosfn_write_char_attr_:                     ; 0xc1e7e LB 0x18d
     rep stosw                                 ; f3 ab
     jmp near 02004h                           ; e9 bb 00
     mov bx, ax                                ; 89 c3
-    mov al, byte [bx+046aeh]                  ; 8a 87 ae 46
+    mov al, byte [bx+046afh]                  ; 8a 87 af 46
     mov bx, ax                                ; 89 c3
     sal bx, 006h                              ; c1 e3 06
-    mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
     mov byte [bp-00eh], al                    ; 88 46 f2
-    mov al, byte [di+04631h]                  ; 8a 85 31 46
+    mov al, byte [di+04632h]                  ; 8a 85 32 46
     mov byte [bp-010h], al                    ; 88 46 f0
     dec si                                    ; 4e
     cmp si, strict byte 0ffffh                ; 83 fe ff
@@ -3933,7 +3933,7 @@ biosfn_write_char_attr_:                     ; 0xc1e7e LB 0x18d
     mov al, byte [bp-014h]                    ; 8a 46 ec
     mov bx, ax                                ; 89 c3
     sal bx, 003h                              ; c1 e3 03
-    mov al, byte [bx+04630h]                  ; 8a 87 30 46
+    mov al, byte [bx+04631h]                  ; 8a 87 31 46
     cmp AL, strict byte 003h                  ; 3c 03
     jc short 01f91h                           ; 72 0c
     jbe short 01f97h                          ; 76 10
@@ -4045,7 +4045,7 @@ biosfn_write_char_only_:                     ; 0xc200b LB 0x196
     xor bh, bh                                ; 30 ff
     mov di, bx                                ; 89 df
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 020d3h                          ; 75 47
     mul word [bp-01ah]                        ; f7 66 e6
     add ax, ax                                ; 01 c0
@@ -4072,20 +4072,20 @@ biosfn_write_char_only_:                     ; 0xc200b LB 0x196
     mov al, byte [bp-00eh]                    ; 8a 46 f2
     mov bx, ax                                ; 89 c3
     sal bx, 003h                              ; c1 e3 03
-    mov ax, word [bx+04632h]                  ; 8b 87 32 46
+    mov ax, word [bx+04633h]                  ; 8b 87 33 46
     mov bx, dx                                ; 89 d3
     mov dx, cx                                ; 89 ca
     call 03173h                               ; e8 a4 10
     inc cx                                    ; 41
     inc cx                                    ; 41
     jmp short 020afh                          ; eb dc
-    mov al, byte [di+046aeh]                  ; 8a 85 ae 46
+    mov al, byte [di+046afh]                  ; 8a 85 af 46
     xor ah, ah                                ; 30 e4
     mov di, ax                                ; 89 c7
     sal di, 006h                              ; c1 e7 06
-    mov al, byte [di+046c4h]                  ; 8a 85 c4 46
+    mov al, byte [di+046c5h]                  ; 8a 85 c5 46
     mov byte [bp-012h], al                    ; 88 46 ee
-    mov al, byte [bx+04631h]                  ; 8a 87 31 46
+    mov al, byte [bx+04632h]                  ; 8a 87 32 46
     mov byte [bp-016h], al                    ; 88 46 ea
     dec si                                    ; 4e
     cmp si, strict byte 0ffffh                ; 83 fe ff
@@ -4097,7 +4097,7 @@ biosfn_write_char_only_:                     ; 0xc200b LB 0x196
     mov al, byte [bp-00eh]                    ; 8a 46 f2
     mov bx, ax                                ; 89 c3
     sal bx, 003h                              ; c1 e3 03
-    mov bl, byte [bx+04630h]                  ; 8a 9f 30 46
+    mov bl, byte [bx+04631h]                  ; 8a 9f 31 46
     cmp bl, 003h                              ; 80 fb 03
     jc short 0211ch                           ; 72 0f
     jbe short 02123h                          ; 76 14
@@ -4185,9 +4185,9 @@ biosfn_write_pixel_:                         ; 0xc21a1 LB 0x17b
     xor ah, ah                                ; 30 e4
     mov bx, ax                                ; 89 c3
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     je short 021edh                           ; 74 18
-    mov al, byte [bx+04630h]                  ; 8a 87 30 46
+    mov al, byte [bx+04631h]                  ; 8a 87 31 46
     cmp AL, strict byte 003h                  ; 3c 03
     jc short 021e9h                           ; 72 0c
     jbe short 021f3h                          ; 76 14
@@ -4247,7 +4247,7 @@ biosfn_write_pixel_:                         ; 0xc21a1 LB 0x17b
     mov ax, cx                                ; 89 c8
     shr ax, 1                                 ; d1 e8
     imul ax, ax, strict byte 00050h           ; 6b c0 50
-    cmp byte [bx+04631h], 002h                ; 80 bf 31 46 02
+    cmp byte [bx+04632h], 002h                ; 80 bf 32 46 02
     jne short 02276h                          ; 75 08
     mov bx, word [bp-00ah]                    ; 8b 5e f6
     shr bx, 002h                              ; c1 eb 02
@@ -4267,7 +4267,7 @@ biosfn_write_pixel_:                         ; 0xc21a1 LB 0x17b
     xor ah, ah                                ; 30 e4
     mov si, ax                                ; 89 c6
     sal si, 003h                              ; c1 e6 03
-    cmp byte [si+04631h], 002h                ; 80 bc 31 46 02
+    cmp byte [si+04632h], 002h                ; 80 bc 32 46 02
     jne short 022bfh                          ; 75 19
     mov al, byte [bp-00ah]                    ; 8a 46 f6
     and AL, strict byte 003h                  ; 24 03
@@ -4391,7 +4391,7 @@ biosfn_write_teletype_:                      ; 0xc231c LB 0x26f
     xor bh, bh                                ; 30 ff
     mov si, bx                                ; 89 de
     sal si, 003h                              ; c1 e6 03
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 02427h                          ; 75 4e
     mov ax, word [bp-018h]                    ; 8b 46 e8
     mul word [bp-01ah]                        ; f7 66 e6
@@ -4413,7 +4413,7 @@ biosfn_write_teletype_:                      ; 0xc231c LB 0x26f
     add ax, ax                                ; 01 c0
     add cx, ax                                ; 01 c1
     mov bl, byte [bp-00eh]                    ; 8a 5e f2
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov dx, cx                                ; 89 ca
     call 03173h                               ; e8 63 0d
     cmp byte [bp-014h], 003h                  ; 80 7e ec 03
@@ -4422,14 +4422,14 @@ biosfn_write_teletype_:                      ; 0xc231c LB 0x26f
     xor bh, bh                                ; 30 ff
     mov dx, cx                                ; 89 ca
     inc dx                                    ; 42
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     call 03173h                               ; e8 4e 0d
     jmp short 02470h                          ; eb 49
-    mov bl, byte [bx+046aeh]                  ; 8a 9f ae 46
+    mov bl, byte [bx+046afh]                  ; 8a 9f af 46
     sal bx, 006h                              ; c1 e3 06
-    mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
-    mov ah, byte [si+04631h]                  ; 8a a4 31 46
-    mov cl, byte [si+04630h]                  ; 8a 8c 30 46
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
+    mov ah, byte [si+04632h]                  ; 8a a4 32 46
+    mov cl, byte [si+04631h]                  ; 8a 8c 31 46
     cmp cl, 003h                              ; 80 f9 03
     jc short 0244dh                           ; 72 0e
     jbe short 02454h                          ; 76 13
@@ -4511,7 +4511,7 @@ biosfn_write_teletype_:                      ; 0xc231c LB 0x26f
     db  0feh, 0c8h
     ; dec al                                    ; fe c8
     mov byte [bp-00ah], al                    ; 88 46 f6
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 02549h                          ; 75 4c
     mov ax, word [bp-018h]                    ; 8b 46 e8
     mul word [bp-01ah]                        ; f7 66 e6
@@ -4532,7 +4532,7 @@ biosfn_write_teletype_:                      ; 0xc231c LB 0x26f
     mov dx, cx                                ; 89 ca
     add dx, ax                                ; 01 c2
     inc dx                                    ; 42
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     call 03165h                               ; e8 36 0c
     push strict byte 00001h                   ; 6a 01
     mov bl, byte [bp-016h]                    ; 8a 5e ea
@@ -4819,7 +4819,7 @@ biosfn_load_text_8_14_pat_:                  ; 0xc2735 LB 0x6e
     mov di, bx                                ; 89 df
     sal di, 005h                              ; c1 e7 05
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 05bech                            ; 81 c6 ec 5b
+    add si, 05bedh                            ; 81 c6 ed 5b
     mov cx, strict word 0000eh                ; b9 0e 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -4874,7 +4874,7 @@ biosfn_load_text_8_8_pat_:                   ; 0xc27a3 LB 0x70
     mov di, bx                                ; 89 df
     sal di, 005h                              ; c1 e7 05
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 053ech                            ; 81 c6 ec 53
+    add si, 053edh                            ; 81 c6 ed 53
     mov cx, strict word 00008h                ; b9 08 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -4929,7 +4929,7 @@ biosfn_load_text_8_16_pat_:                  ; 0xc2813 LB 0x70
     mov di, bx                                ; 89 df
     sal di, 005h                              ; c1 e7 05
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 069ech                            ; 81 c6 ec 69
+    add si, 069edh                            ; 81 c6 ed 69
     mov cx, strict word 00010h                ; b9 10 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -5070,7 +5070,7 @@ biosfn_read_state_info_:                     ; 0xc294f LB 0x102
     push dx                                   ; 52
     push bx                                   ; 53
     mov cx, ds                                ; 8c d9
-    mov bx, 05382h                            ; bb 82 53
+    mov bx, 05383h                            ; bb 83 53
     mov dx, word [bp-00ah]                    ; 8b 56 f6
     mov ax, word [bp-008h]                    ; 8b 46 f8
     call 031afh                               ; e8 4a 08
@@ -6007,7 +6007,7 @@ find_vga_entry_:                             ; 0xc313d LB 0x28
     mov bl, al                                ; 88 c3
     xor bh, bh                                ; 30 ff
     sal bx, 003h                              ; c1 e3 03
-    cmp dl, byte [bx+0462eh]                  ; 3a 97 2e 46
+    cmp dl, byte [bx+0462fh]                  ; 3a 97 2f 46
     jne short 0314ah                          ; 75 ed
     mov ah, al                                ; 88 c4
     mov al, ah                                ; 88 e0
@@ -7291,10 +7291,10 @@ vesa_pm_end:                                 ; 0xc4514 LB 0x1
   ; Padding 0xeb bytes at 0xc4515
   times 235 db 0
 
-section _DATA progbits vstart=0x4600 align=1 ; size=0x371e class=DATA group=DGROUP
-_msg_vga_init:                               ; 0xc4600 LB 0x2e
-    db  'Oracle VM VirtualBox Version 5.1.8 VGA BIOS', 00dh, 00ah, 000h
-_vga_modes:                                  ; 0xc462e LB 0x80
+section _DATA progbits vstart=0x4600 align=1 ; size=0x371f class=DATA group=DGROUP
+_msg_vga_init:                               ; 0xc4600 LB 0x2f
+    db  'Oracle VM VirtualBox Version 5.1.10 VGA BIOS', 00dh, 00ah, 000h
+_vga_modes:                                  ; 0xc462f LB 0x80
     db  000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
     db  002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
     db  004h, 001h, 002h, 002h, 000h, 0b8h, 0ffh, 001h, 005h, 001h, 002h, 002h, 000h, 0b8h, 0ffh, 001h
@@ -7303,11 +7303,11 @@ _vga_modes:                                  ; 0xc462e LB 0x80
     db  00fh, 001h, 003h, 001h, 000h, 0a0h, 0ffh, 000h, 010h, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
     db  011h, 001h, 003h, 001h, 000h, 0a0h, 0ffh, 002h, 012h, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
     db  013h, 001h, 005h, 008h, 000h, 0a0h, 0ffh, 003h, 06ah, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
-_line_to_vpti:                               ; 0xc46ae LB 0x10
+_line_to_vpti:                               ; 0xc46af LB 0x10
     db  017h, 017h, 018h, 018h, 004h, 005h, 006h, 007h, 00dh, 00eh, 011h, 012h, 01ah, 01bh, 01ch, 01dh
-_dac_regs:                                   ; 0xc46be LB 0x4
+_dac_regs:                                   ; 0xc46bf LB 0x4
     dd  0ff3f3f3fh
-_video_param_table:                          ; 0xc46c2 LB 0x780
+_video_param_table:                          ; 0xc46c3 LB 0x780
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
@@ -7428,7 +7428,7 @@ _video_param_table:                          ; 0xc46c2 LB 0x780
     db  072h, 0f0h, 000h, 060h, 000h, 000h, 000h, 000h, 000h, 000h, 059h, 08dh, 057h, 032h, 000h, 057h
     db  073h, 0e3h, 0ffh, 000h, 001h, 002h, 003h, 004h, 005h, 014h, 007h, 038h, 039h, 03ah, 03bh, 03ch
     db  03dh, 03eh, 03fh, 001h, 000h, 00fh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 005h, 00fh, 0ffh
-_palette0:                                   ; 0xc4e42 LB 0xc0
+_palette0:                                   ; 0xc4e43 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
@@ -7441,7 +7441,7 @@ _palette0:                                   ; 0xc4e42 LB 0xc0
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
     db  03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
-_palette1:                                   ; 0xc4f02 LB 0xc0
+_palette1:                                   ; 0xc4f03 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah
     db  000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah, 000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah
@@ -7454,7 +7454,7 @@ _palette1:                                   ; 0xc4f02 LB 0xc0
     db  015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh, 015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh
     db  015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
-_palette2:                                   ; 0xc4fc2 LB 0xc0
+_palette2:                                   ; 0xc4fc3 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 02ah, 000h, 02ah, 02ah, 02ah, 000h, 000h, 015h, 000h, 000h, 03fh, 000h, 02ah
     db  015h, 000h, 02ah, 03fh, 02ah, 000h, 015h, 02ah, 000h, 03fh, 02ah, 02ah, 015h, 02ah, 02ah, 03fh
@@ -7467,7 +7467,7 @@ _palette2:                                   ; 0xc4fc2 LB 0xc0
     db  015h, 015h, 000h, 015h, 015h, 02ah, 015h, 03fh, 000h, 015h, 03fh, 02ah, 03fh, 015h, 000h, 03fh
     db  015h, 02ah, 03fh, 03fh, 000h, 03fh, 03fh, 02ah, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
-_palette3:                                   ; 0xc5082 LB 0x300
+_palette3:                                   ; 0xc5083 LB 0x300
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
@@ -7516,19 +7516,19 @@ _palette3:                                   ; 0xc5082 LB 0x300
     db  00bh, 010h, 00bh, 00bh, 010h, 00ch, 00bh, 010h, 00dh, 00bh, 010h, 00fh, 00bh, 010h, 010h, 00bh
     db  00fh, 010h, 00bh, 00dh, 010h, 00bh, 00ch, 010h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_static_functionality:                       ; 0xc5382 LB 0x10
+_static_functionality:                       ; 0xc5383 LB 0x10
     db  0ffh, 0e0h, 00fh, 000h, 000h, 000h, 000h, 007h, 002h, 008h, 0e7h, 00ch, 000h, 000h, 000h, 000h
-_dcc_table:                                  ; 0xc5392 LB 0x24
+_dcc_table:                                  ; 0xc5393 LB 0x24
     db  010h, 001h, 007h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h
-_secondary_save_area:                        ; 0xc53b6 LB 0x1a
-    db  01ah, 000h, 092h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+_secondary_save_area:                        ; 0xc53b7 LB 0x1a
+    db  01ah, 000h, 093h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_video_save_pointer_table:                   ; 0xc53d0 LB 0x1c
-    db  0c2h, 046h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  0b6h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont8:                                   ; 0xc53ec LB 0x800
+_video_save_pointer_table:                   ; 0xc53d1 LB 0x1c
+    db  0c3h, 046h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+    db  0b7h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+_vgafont8:                                   ; 0xc53ed LB 0x800
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07eh, 081h, 0a5h, 081h, 0bdh, 099h, 081h, 07eh
     db  07eh, 0ffh, 0dbh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh, 06ch, 0feh, 0feh, 0feh, 07ch, 038h, 010h, 000h
     db  010h, 038h, 07ch, 0feh, 07ch, 038h, 010h, 000h, 038h, 07ch, 038h, 0feh, 0feh, 07ch, 038h, 07ch
@@ -7657,7 +7657,7 @@ _vgafont8:                                   ; 0xc53ec LB 0x800
     db  000h, 000h, 000h, 000h, 018h, 000h, 000h, 000h, 00fh, 00ch, 00ch, 00ch, 0ech, 06ch, 03ch, 01ch
     db  078h, 06ch, 06ch, 06ch, 06ch, 000h, 000h, 000h, 070h, 018h, 030h, 060h, 078h, 000h, 000h, 000h
     db  000h, 000h, 03ch, 03ch, 03ch, 03ch, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont14:                                  ; 0xc5bec LB 0xe00
+_vgafont14:                                  ; 0xc5bed LB 0xe00
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  07eh, 081h, 0a5h, 081h, 081h, 0bdh, 099h, 081h, 07eh, 000h, 000h, 000h, 000h, 000h, 07eh, 0ffh
     db  0dbh, 0ffh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh, 000h, 000h, 000h, 000h, 000h, 000h, 06ch, 0feh, 0feh
@@ -7882,7 +7882,7 @@ _vgafont14:                                  ; 0xc5bec LB 0xe00
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 070h, 0d8h, 030h, 060h, 0c8h, 0f8h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont16:                                  ; 0xc69ec LB 0x1000
+_vgafont16:                                  ; 0xc69ed LB 0x1000
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 07eh, 081h, 0a5h, 081h, 081h, 0bdh, 099h, 081h, 081h, 07eh, 000h, 000h, 000h, 000h
     db  000h, 000h, 07eh, 0ffh, 0dbh, 0ffh, 0ffh, 0c3h, 0e7h, 0ffh, 0ffh, 07eh, 000h, 000h, 000h, 000h
@@ -8139,7 +8139,7 @@ _vgafont16:                                  ; 0xc69ec LB 0x1000
     db  000h, 070h, 0d8h, 030h, 060h, 0c8h, 0f8h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont14alt:                               ; 0xc79ec LB 0x12d
+_vgafont14alt:                               ; 0xc79ed LB 0x12d
     db  01dh, 000h, 000h, 000h, 000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h, 000h, 000h, 000h, 022h
     db  000h, 063h, 063h, 063h, 022h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 02bh, 000h
     db  000h, 000h, 018h, 018h, 018h, 0ffh, 018h, 018h, 018h, 000h, 000h, 000h, 000h, 02dh, 000h, 000h
@@ -8159,7 +8159,7 @@ _vgafont14alt:                               ; 0xc79ec LB 0x12d
     db  000h, 0fch, 066h, 066h, 07ch, 062h, 066h, 06fh, 066h, 066h, 0f3h, 000h, 000h, 000h, 0f1h, 000h
     db  000h, 018h, 018h, 018h, 0ffh, 018h, 018h, 018h, 000h, 0ffh, 000h, 000h, 000h, 0f6h, 000h, 000h
     db  018h, 018h, 000h, 000h, 0ffh, 000h, 000h, 018h, 018h, 000h, 000h, 000h, 000h
-_vgafont16alt:                               ; 0xc7b19 LB 0x145
+_vgafont16alt:                               ; 0xc7b1a LB 0x144
     db  01dh, 000h, 000h, 000h, 000h, 000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h, 000h, 000h, 000h
     db  000h, 030h, 000h, 000h, 03ch, 066h, 0c3h, 0c3h, 0dbh, 0dbh, 0c3h, 0c3h, 066h, 03ch, 000h, 000h
     db  000h, 000h, 04dh, 000h, 000h, 0c3h, 0e7h, 0ffh, 0ffh, 0dbh, 0c3h, 0c3h, 0c3h, 0c3h, 0c3h, 000h
@@ -8180,32 +8180,34 @@ _vgafont16alt:                               ; 0xc7b19 LB 0x145
     db  09eh, 000h, 0fch, 066h, 066h, 07ch, 062h, 066h, 06fh, 066h, 066h, 066h, 0f3h, 000h, 000h, 000h
     db  000h, 0abh, 000h, 0c0h, 0c0h, 0c2h, 0c6h, 0cch, 018h, 030h, 060h, 0ceh, 09bh, 006h, 00ch, 01fh
     db  000h, 000h, 0ach, 000h, 0c0h, 0c0h, 0c2h, 0c6h, 0cch, 018h, 030h, 066h, 0ceh, 096h, 03eh, 006h
-    db  006h, 000h, 000h, 000h, 000h
+    db  006h, 000h, 000h, 000h
 _vbebios_copyright:                          ; 0xc7c5e LB 0x15
     db  'VirtualBox VESA BIOS', 000h
 _vbebios_vendor_name:                        ; 0xc7c73 LB 0x13
     db  'Oracle Corporation', 000h
 _vbebios_product_name:                       ; 0xc7c86 LB 0x21
     db  'Oracle VM VirtualBox VBE Adapter', 000h
-_vbebios_product_revision:                   ; 0xc7ca7 LB 0x23
-    db  'Oracle VM VirtualBox Version 5.1.8', 000h
-_vbebios_info_string:                        ; 0xc7cca LB 0x2b
+_vbebios_product_revision:                   ; 0xc7ca7 LB 0x24
+    db  'Oracle VM VirtualBox Version 5.1.10', 000h
+_vbebios_info_string:                        ; 0xc7ccb LB 0x2b
     db  'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
-_no_vbebios_info_string:                     ; 0xc7cf5 LB 0x29
+_no_vbebios_info_string:                     ; 0xc7cf6 LB 0x29
     db  'No VirtualBox VBE support available!', 00dh, 00ah, 00dh, 00ah, 000h
 
-section CONST progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
+  ; Padding 0x1 bytes at 0xc7d1f
+    db  001h
 
-section CONST2 progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
+section CONST progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
 
-  ; Padding 0x2e2 bytes at 0xc7d1e
-    db  001h, 000h, 000h, 000h, 000h, 001h, 000h, 000h, 000h, 000h, 000h, 000h, 02fh, 068h, 06fh, 06dh
-    db  065h, 02fh, 066h, 06dh, 033h, 02fh, 073h, 072h, 063h, 02fh, 076h, 062h, 06fh, 078h, 02dh, 035h
-    db  02eh, 031h, 02fh, 06fh, 075h, 074h, 02fh, 06ch, 069h, 06eh, 075h, 078h, 02eh, 061h, 06dh, 064h
-    db  036h, 034h, 02fh, 072h, 065h, 06ch, 065h, 061h, 073h, 065h, 02fh, 06fh, 062h, 06ah, 02fh, 056h
-    db  042h, 06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 032h, 038h, 036h, 02fh, 056h, 042h
-    db  06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 032h, 038h, 036h, 02eh, 073h, 079h, 06dh
-    db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+section CONST2 progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
+
+  ; Padding 0x2e0 bytes at 0xc7d20
+    db  000h, 000h, 000h, 000h, 001h, 000h, 000h, 000h, 000h, 000h, 000h, 02fh, 068h, 06fh, 06dh, 065h
+    db  02fh, 066h, 06dh, 033h, 02fh, 073h, 072h, 063h, 02fh, 076h, 062h, 06fh, 078h, 02dh, 035h, 02eh
+    db  031h, 02fh, 06fh, 075h, 074h, 02fh, 06ch, 069h, 06eh, 075h, 078h, 02eh, 061h, 06dh, 064h, 036h
+    db  034h, 02fh, 072h, 065h, 06ch, 065h, 061h, 073h, 065h, 02fh, 06fh, 062h, 06ah, 02fh, 056h, 042h
+    db  06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 032h, 038h, 036h, 02fh, 056h, 042h, 06fh
+    db  078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 032h, 038h, 036h, 02eh, 073h, 079h, 06dh, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
@@ -8245,4 +8247,4 @@ section CONST2 progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  000h, 078h
+    db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0c8h
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
index 17574cb..67f93bb 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
@@ -1 +1 @@
-9234056c02f1c75e16b92de939e14af2 *VBoxVgaBios286.rom
+71e918fddfdff2a98a7919d285dc4d37 *VBoxVgaBios286.rom
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
index 42f8efa..e2ef207 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
@@ -1651,7 +1651,7 @@ vga_read_char_attr_:                         ; 0xc0acb LB 0xa8
     call 02f5ah                               ; e8 3a 24
     movzx bx, ch                              ; 0f b6 dd
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 00b5ah                          ; 75 2d
     mov dx, ax                                ; 89 c2
     imul dx, di                               ; 0f af d7
@@ -1667,7 +1667,7 @@ vga_read_char_attr_:                         ; 0xc0acb LB 0xa8
     add ax, ax                                ; 01 c0
     mov dx, cx                                ; 89 ca
     add dx, ax                                ; 01 c2
-    mov ax, word [bx+04632h]                  ; 8b 87 32 46
+    mov ax, word [bx+04633h]                  ; 8b 87 33 46
     call 02f5ah                               ; e8 03 24
     mov word [ss:si], ax                      ; 36 89 04
     lea sp, [bp-008h]                         ; 8d 66 f8
@@ -1733,18 +1733,18 @@ vga_get_font_info_:                          ; 0xc0b73 LB 0x82
     retn 00002h                               ; c2 02 00
     mov dx, 0010ch                            ; ba 0c 01
     jmp short 00b91h                          ; eb bf
-    mov ax, 05bech                            ; b8 ec 5b
+    mov ax, 05bedh                            ; b8 ed 5b
     mov dx, 0c000h                            ; ba 00 c0
     jmp short 00b96h                          ; eb bc
-    mov ax, 053ech                            ; b8 ec 53
+    mov ax, 053edh                            ; b8 ed 53
     jmp short 00bd5h                          ; eb f6
-    mov ax, 057ech                            ; b8 ec 57
+    mov ax, 057edh                            ; b8 ed 57
     jmp short 00bd5h                          ; eb f1
-    mov ax, 079ech                            ; b8 ec 79
+    mov ax, 079edh                            ; b8 ed 79
     jmp short 00bd5h                          ; eb ec
-    mov ax, 069ech                            ; b8 ec 69
+    mov ax, 069edh                            ; b8 ed 69
     jmp short 00bd5h                          ; eb e7
-    mov ax, 07b19h                            ; b8 19 7b
+    mov ax, 07b1ah                            ; b8 1a 7b
     jmp short 00bd5h                          ; eb e2
     jmp short 00bc4h                          ; eb cf
 vga_read_pixel_:                             ; 0xc0bf5 LB 0x139
@@ -1766,9 +1766,9 @@ vga_read_pixel_:                             ; 0xc0bf5 LB 0x139
     je near 00d27h                            ; 0f 84 0d 01
     movzx bx, al                              ; 0f b6 d8
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     je near 00d27h                            ; 0f 84 fe 00
-    mov bl, byte [bx+04630h]                  ; 8a 9f 30 46
+    mov bl, byte [bx+04631h]                  ; 8a 9f 31 46
     cmp bl, 003h                              ; 80 fb 03
     jc short 00c43h                           ; 72 11
     jbe short 00c4bh                          ; 76 17
@@ -1827,7 +1827,7 @@ vga_read_pixel_:                             ; 0xc0bf5 LB 0x139
     call 02f3eh                               ; e8 7b 22
     movzx bx, cl                              ; 0f b6 d9
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+04631h], 002h                ; 80 bf 31 46 02
+    cmp byte [bx+04632h], 002h                ; 80 bf 32 46 02
     jne short 00cebh                          ; 75 1b
     mov cx, si                                ; 89 f1
     xor ch, ch                                ; 30 ed
@@ -2128,7 +2128,7 @@ biosfn_set_active_page_:                     ; 0xc0f00 LB 0xdc
     movzx bx, ch                              ; 0f b6 dd
     mov si, bx                                ; 89 de
     sal si, 003h                              ; c1 e6 03
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 00f83h                          ; 75 40
     mov dx, strict word 0004ah                ; ba 4a 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2155,10 +2155,10 @@ biosfn_set_active_page_:                     ; 0xc0f00 LB 0xdc
     lea bx, [si+001h]                         ; 8d 5c 01
     imul bx, di                               ; 0f af df
     jmp short 00f95h                          ; eb 12
-    movzx bx, byte [bx+046aeh]                ; 0f b6 9f ae 46
+    movzx bx, byte [bx+046afh]                ; 0f b6 9f af 46
     sal bx, 006h                              ; c1 e3 06
     movzx ax, cl                              ; 0f b6 c1
-    mov bx, word [bx+046c5h]                  ; 8b 9f c5 46
+    mov bx, word [bx+046c6h]                  ; 8b 9f c6 46
     imul bx, ax                               ; 0f af d8
     mov dx, strict word 00063h                ; ba 63 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2226,15 +2226,15 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     cmp AL, strict byte 0ffh                  ; 3c ff
     je near 01363h                            ; 0f 84 43 03
     movzx si, al                              ; 0f b6 f0
-    mov al, byte [si+046aeh]                  ; 8a 84 ae 46
+    mov al, byte [si+046afh]                  ; 8a 84 af 46
     mov byte [bp-00eh], al                    ; 88 46 f2
     movzx bx, al                              ; 0f b6 d8
     sal bx, 006h                              ; c1 e3 06
-    movzx ax, byte [bx+046c2h]                ; 0f b6 87 c2 46
-    mov word [bp-018h], ax                    ; 89 46 e8
     movzx ax, byte [bx+046c3h]                ; 0f b6 87 c3 46
-    mov word [bp-016h], ax                    ; 89 46 ea
+    mov word [bp-018h], ax                    ; 89 46 e8
     movzx ax, byte [bx+046c4h]                ; 0f b6 87 c4 46
+    mov word [bp-016h], ax                    ; 89 46 ea
+    movzx ax, byte [bx+046c5h]                ; 0f b6 87 c5 46
     mov word [bp-014h], ax                    ; 89 46 ec
     mov dx, 00087h                            ; ba 87 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2250,13 +2250,13 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     jne near 010f5h                           ; 0f 85 8a 00
     mov bx, si                                ; 89 f3
     sal bx, 003h                              ; c1 e3 03
-    mov al, byte [bx+04634h]                  ; 8a 87 34 46
+    mov al, byte [bx+04635h]                  ; 8a 87 35 46
     mov dx, 003c6h                            ; ba c6 03
     out DX, AL                                ; ee
     xor al, al                                ; 30 c0
     mov dx, 003c8h                            ; ba c8 03
     out DX, AL                                ; ee
-    mov bl, byte [bx+04635h]                  ; 8a 9f 35 46
+    mov bl, byte [bx+04636h]                  ; 8a 9f 36 46
     cmp bl, 001h                              ; 80 fb 01
     jc short 01095h                           ; 72 0e
     jbe short 0109eh                          ; 76 15
@@ -2267,13 +2267,13 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     jmp short 010abh                          ; eb 16
     test bl, bl                               ; 84 db
     jne short 010abh                          ; 75 12
-    mov di, 04e42h                            ; bf 42 4e
+    mov di, 04e43h                            ; bf 43 4e
     jmp short 010abh                          ; eb 0d
-    mov di, 04f02h                            ; bf 02 4f
+    mov di, 04f03h                            ; bf 03 4f
     jmp short 010abh                          ; eb 08
-    mov di, 04fc2h                            ; bf c2 4f
+    mov di, 04fc3h                            ; bf c3 4f
     jmp short 010abh                          ; eb 03
-    mov di, 05082h                            ; bf 82 50
+    mov di, 05083h                            ; bf 83 50
     xor bx, bx                                ; 31 db
     jmp short 010beh                          ; eb 0f
     xor al, al                                ; 30 c0
@@ -2286,8 +2286,8 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     jnc short 010e8h                          ; 73 2a
     movzx si, byte [bp-012h]                  ; 0f b6 76 ee
     sal si, 003h                              ; c1 e6 03
-    movzx si, byte [si+04635h]                ; 0f b6 b4 35 46
-    movzx dx, byte [si+046beh]                ; 0f b6 94 be 46
+    movzx si, byte [si+04636h]                ; 0f b6 b4 36 46
+    movzx dx, byte [si+046bfh]                ; 0f b6 94 bf 46
     cmp bx, dx                                ; 39 d3
     jnbe short 010afh                         ; 77 dc
     imul si, bx, strict byte 00003h           ; 6b f3 03
@@ -2319,7 +2319,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 006h                              ; c1 e6 06
     add si, bx                                ; 01 de
-    mov al, byte [si+046e5h]                  ; 8a 84 e5 46
+    mov al, byte [si+046e6h]                  ; 8a 84 e6 46
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 010ffh                          ; eb e4
@@ -2343,7 +2343,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 006h                              ; c1 e6 06
     add si, bx                                ; 01 de
-    mov al, byte [si+046c6h]                  ; 8a 84 c6 46
+    mov al, byte [si+046c7h]                  ; 8a 84 c7 46
     mov dx, 003c5h                            ; ba c5 03
     out DX, AL                                ; ee
     inc bx                                    ; 43
@@ -2358,14 +2358,14 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 006h                              ; c1 e6 06
     add si, bx                                ; 01 de
-    mov al, byte [si+046f9h]                  ; 8a 84 f9 46
+    mov al, byte [si+046fah]                  ; 8a 84 fa 46
     mov dx, 003cfh                            ; ba cf 03
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 01156h                          ; eb e1
     movzx bx, byte [bp-012h]                  ; 0f b6 5e ee
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+04630h], 001h                ; 80 bf 30 46 01
+    cmp byte [bx+04631h], 001h                ; 80 bf 31 46 01
     jne short 01188h                          ; 75 05
     mov dx, 003b4h                            ; ba b4 03
     jmp short 0118bh                          ; eb 03
@@ -2385,12 +2385,12 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     mov di, cx                                ; 89 cf
     add di, bx                                ; 01 df
     lea dx, [si+001h]                         ; 8d 54 01
-    mov al, byte [di+046cch]                  ; 8a 85 cc 46
+    mov al, byte [di+046cdh]                  ; 8a 85 cd 46
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 01195h                          ; eb e0
     mov bx, cx                                ; 89 cb
-    mov al, byte [bx+046cbh]                  ; 8a 87 cb 46
+    mov al, byte [bx+046cch]                  ; 8a 87 cc 46
     mov dx, 003c2h                            ; ba c2 03
     out DX, AL                                ; ee
     mov AL, strict byte 020h                  ; b0 20
@@ -2404,9 +2404,9 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     jne short 01230h                          ; 75 5f
     movzx bx, byte [bp-012h]                  ; 0f b6 5e ee
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 011f2h                          ; 75 13
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 04000h                            ; b9 00 40
     mov ax, 00720h                            ; b8 20 07
     xor di, di                                ; 31 ff
@@ -2416,7 +2416,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     jmp short 01230h                          ; eb 3e
     cmp byte [bp-00ch], 00dh                  ; 80 7e f4 0d
     jnc short 0120ah                          ; 73 12
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 04000h                            ; b9 00 40
     xor ax, ax                                ; 31 c0
     xor di, di                                ; 31 ff
@@ -2434,7 +2434,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     mov word [bp-01ah], ax                    ; 89 46 e6
     mov AL, strict byte 00fh                  ; b0 0f
     out DX, AL                                ; ee
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 08000h                            ; b9 00 80
     xor ax, ax                                ; 31 c0
     xor di, di                                ; 31 ff
@@ -2453,7 +2453,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     call 02f68h                               ; e8 1f 1d
     movzx bx, byte [bp-00eh]                  ; 0f b6 5e f2
     sal bx, 006h                              ; c1 e3 06
-    mov bx, word [bx+046c5h]                  ; 8b 9f c5 46
+    mov bx, word [bx+046c6h]                  ; 8b 9f c6 46
     mov dx, strict word 0004ch                ; ba 4c 00
     mov ax, strict word 00040h                ; b8 40 00
     call 02f68h                               ; e8 0b 1d
@@ -2492,7 +2492,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     mov ax, strict word 00040h                ; b8 40 00
     call 02f4ch                               ; e8 8b 1c
     mov cx, ds                                ; 8c d9
-    mov bx, 053d0h                            ; bb d0 53
+    mov bx, 053d1h                            ; bb d1 53
     mov dx, 000a8h                            ; ba a8 00
     mov ax, strict word 00040h                ; b8 40 00
     call 02f88h                               ; e8 b9 1c
@@ -2506,7 +2506,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     call 02f4ch                               ; e8 67 1c
     movzx bx, byte [bp-012h]                  ; 0f b6 5e ee
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 012fch                          ; 75 09
     mov dx, strict word 00007h                ; ba 07 00
     mov ax, strict word 00006h                ; b8 06 00
@@ -2524,7 +2524,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     call 00f00h                               ; e8 eb fb
     movzx bx, byte [bp-012h]                  ; 0f b6 5e ee
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 01333h                          ; 75 10
     xor bl, bl                                ; 30 db
     mov AL, strict byte 004h                  ; b0 04
@@ -2534,7 +2534,7 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     mov AL, strict byte 003h                  ; b0 03
     mov AH, strict byte 011h                  ; b4 11
     int 010h                                  ; cd 10
-    mov dx, 057ech                            ; ba ec 57
+    mov dx, 057edh                            ; ba ed 57
     mov ax, strict word 0001fh                ; b8 1f 00
     call 00a00h                               ; e8 c4 f6
     mov ax, word [bp-014h]                    ; 8b 46 ec
@@ -2544,13 +2544,13 @@ biosfn_set_video_mode_:                      ; 0xc0fdc LB 0x391
     je short 01359h                           ; 74 10
     cmp ax, strict word 00008h                ; 3d 08 00
     jne short 01363h                          ; 75 15
-    mov dx, 053ech                            ; ba ec 53
+    mov dx, 053edh                            ; ba ed 53
     mov ax, strict word 00043h                ; b8 43 00
     call 00a00h                               ; e8 a9 f6
     jmp short 01363h                          ; eb 0a
-    mov dx, 05bech                            ; ba ec 5b
+    mov dx, 05bedh                            ; ba ed 5b
     jmp short 01351h                          ; eb f3
-    mov dx, 069ech                            ; ba ec 69
+    mov dx, 069edh                            ; ba ed 69
     jmp short 01351h                          ; eb ee
     lea sp, [bp-00ah]                         ; 8d 66 f6
     pop di                                    ; 5f
@@ -2860,7 +2860,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     mov word [bp-01ah], ax                    ; 89 46 e6
     mov ax, word [bp-016h]                    ; 8b 46 ea
     imul ax, cx                               ; 0f af c1
-    cmp byte [di+0462fh], 000h                ; 80 bd 2f 46 00
+    cmp byte [di+04630h], 000h                ; 80 bd 30 46 00
     jne near 017d1h                           ; 0f 85 9f 01
     mov dx, ax                                ; 89 c2
     add dx, ax                                ; 01 c2
@@ -2883,7 +2883,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     movzx dx, byte [bp-00ch]                  ; 0f b6 56 f4
     sal dx, 008h                              ; c1 e2 08
     add dx, strict byte 00020h                ; 83 c2 20
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, ax                                ; 89 c1
     mov ax, dx                                ; 89 d0
     mov di, bx                                ; 89 df
@@ -2917,7 +2917,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     add di, dx                                ; 01 d7
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 003h                              ; c1 e6 03
-    mov es, [si+04632h]                       ; 8e 84 32 46
+    mov es, [si+04633h]                       ; 8e 84 33 46
     cld                                       ; fc
     jcxz 016ddh                               ; e3 02
     rep stosw                                 ; f3 ab
@@ -2931,7 +2931,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     add dx, dx                                ; 01 d2
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 003h                              ; c1 e6 03
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov si, word [bp-014h]                    ; 8b 76 ec
     imul si, word [bp-016h]                   ; 0f af 76 ea
     add cx, si                                ; 01 f1
@@ -2975,7 +2975,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     add di, dx                                ; 01 d7
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 003h                              ; c1 e6 03
-    mov es, [si+04632h]                       ; 8e 84 32 46
+    mov es, [si+04633h]                       ; 8e 84 33 46
     cld                                       ; fc
     jcxz 0177eh                               ; e3 02
     rep stosw                                 ; f3 ab
@@ -2990,7 +2990,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     add dx, dx                                ; 01 d2
     movzx si, byte [bp-00eh]                  ; 0f b6 76 f2
     sal si, 003h                              ; c1 e6 03
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov si, word [bp-014h]                    ; 8b 76 ec
     imul si, word [bp-016h]                   ; 0f af 76 ea
     add di, si                                ; 01 f7
@@ -3010,11 +3010,11 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     jc near 01a6fh                            ; 0f 82 a4 02
     dec word [bp-014h]                        ; ff 4e ec
     jmp near 0172dh                           ; e9 5c ff
-    movzx bx, byte [si+046aeh]                ; 0f b6 9c ae 46
+    movzx bx, byte [si+046afh]                ; 0f b6 9c af 46
     sal bx, 006h                              ; c1 e3 06
-    mov dl, byte [bx+046c4h]                  ; 8a 97 c4 46
+    mov dl, byte [bx+046c5h]                  ; 8a 97 c5 46
     mov byte [bp-00ah], dl                    ; 88 56 f6
-    mov bl, byte [di+04630h]                  ; 8a 9d 30 46
+    mov bl, byte [di+04631h]                  ; 8a 9d 31 46
     cmp bl, 004h                              ; 80 fb 04
     je short 017f8h                           ; 74 0f
     cmp bl, 003h                              ; 80 fb 03
@@ -3047,7 +3047,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     movzx ax, byte [bp-00ch]                  ; 0f b6 46 f4
     movzx bx, byte [bp-00eh]                  ; 0f b6 5e f2
     sal bx, 003h                              ; c1 e3 03
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     xor di, di                                ; 31 ff
     cld                                       ; fc
     jcxz 01849h                               ; e3 02
@@ -3129,7 +3129,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     jc near 01a6fh                            ; 0f 82 3d 01
     dec word [bp-014h]                        ; ff 4e ec
     jmp short 018c6h                          ; eb 8f
-    mov dl, byte [di+04631h]                  ; 8a 95 31 46
+    mov dl, byte [di+04632h]                  ; 8a 95 32 46
     cmp byte [bp-010h], 000h                  ; 80 7e f0 00
     jne short 0197eh                          ; 75 3d
     cmp byte [bp-008h], 000h                  ; 80 7e f8 00
@@ -3147,7 +3147,7 @@ biosfn_scroll_:                              ; 0xc1572 LB 0x506
     movzx cx, dl                              ; 0f b6 ca
     imul cx, ax                               ; 0f af c8
     movzx ax, byte [bp-00ch]                  ; 0f b6 46 f4
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     xor di, di                                ; 31 ff
     cld                                       ; fc
     jcxz 0197bh                               ; e3 02
@@ -3249,11 +3249,11 @@ write_gfx_char_pl4_:                         ; 0xc1a78 LB 0xeb
     je short 01a96h                           ; 74 0b
     cmp byte [bp+006h], 00eh                  ; 80 7e 06 0e
     jne short 01a9bh                          ; 75 0a
-    mov di, 05bech                            ; bf ec 5b
+    mov di, 05bedh                            ; bf ed 5b
     jmp short 01a9eh                          ; eb 08
-    mov di, 069ech                            ; bf ec 69
+    mov di, 069edh                            ; bf ed 69
     jmp short 01a9eh                          ; eb 03
-    mov di, 053ech                            ; bf ec 53
+    mov di, 053edh                            ; bf ed 53
     movzx si, cl                              ; 0f b6 f1
     movzx bx, byte [bp+006h]                  ; 0f b6 5e 06
     imul si, bx                               ; 0f af f3
@@ -3340,7 +3340,7 @@ write_gfx_char_cga_:                         ; 0xc1b63 LB 0x11e
     push di                                   ; 57
     sub sp, strict byte 00008h                ; 83 ec 08
     mov byte [bp-008h], dl                    ; 88 56 f8
-    mov si, 053ech                            ; be ec 53
+    mov si, 053edh                            ; be ed 53
     xor bh, bh                                ; 30 ff
     movzx di, byte [bp+006h]                  ; 0f b6 7e 06
     imul di, bx                               ; 0f af fb
@@ -3454,7 +3454,7 @@ write_gfx_char_lin_:                         ; 0xc1c81 LB 0x91
     push di                                   ; 57
     sub sp, strict byte 00008h                ; 83 ec 08
     mov byte [bp-006h], dl                    ; 88 56 fa
-    mov di, 053ech                            ; bf ec 53
+    mov di, 053edh                            ; bf ed 53
     movzx dx, cl                              ; 0f b6 d1
     movzx cx, byte [bp+004h]                  ; 0f b6 4e 04
     imul cx, dx                               ; 0f af ca
@@ -3549,7 +3549,7 @@ biosfn_write_char_attr_:                     ; 0xc1d12 LB 0x168
     movzx bx, cl                              ; 0f b6 d9
     mov di, bx                                ; 89 df
     sal di, 003h                              ; c1 e7 03
-    cmp byte [di+0462fh], 000h                ; 80 bd 2f 46 00
+    cmp byte [di+04630h], 000h                ; 80 bd 30 46 00
     jne short 01dcdh                          ; 75 47
     mov bx, word [bp-018h]                    ; 8b 5e e8
     imul bx, ax                               ; 0f af d8
@@ -3570,18 +3570,18 @@ biosfn_write_char_attr_:                     ; 0xc1d12 LB 0x168
     add ax, bx                                ; 01 d8
     mov word [bp-01ah], ax                    ; 89 46 e6
     mov ax, word [bp-01ah]                    ; 8b 46 e6
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, si                                ; 89 f1
     mov di, dx                                ; 89 d7
     cld                                       ; fc
     jcxz 01dcah                               ; e3 02
     rep stosw                                 ; f3 ab
     jmp near 01e73h                           ; e9 a6 00
-    movzx bx, byte [bx+046aeh]                ; 0f b6 9f ae 46
+    movzx bx, byte [bx+046afh]                ; 0f b6 9f af 46
     sal bx, 006h                              ; c1 e3 06
-    mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
     mov byte [bp-008h], al                    ; 88 46 f8
-    mov al, byte [di+04631h]                  ; 8a 85 31 46
+    mov al, byte [di+04632h]                  ; 8a 85 32 46
     mov byte [bp-014h], al                    ; 88 46 ec
     dec si                                    ; 4e
     cmp si, strict byte 0ffffh                ; 83 fe ff
@@ -3591,7 +3591,7 @@ biosfn_write_char_attr_:                     ; 0xc1d12 LB 0x168
     jnc near 01e73h                           ; 0f 83 7d 00
     movzx bx, byte [bp-006h]                  ; 0f b6 5e fa
     sal bx, 003h                              ; c1 e3 03
-    mov al, byte [bx+04630h]                  ; 8a 87 30 46
+    mov al, byte [bx+04631h]                  ; 8a 87 31 46
     cmp AL, strict byte 003h                  ; 3c 03
     jc short 01e11h                           ; 72 0c
     jbe short 01e17h                          ; 76 10
@@ -3679,7 +3679,7 @@ biosfn_write_char_only_:                     ; 0xc1e7a LB 0x16f
     movzx di, cl                              ; 0f b6 f9
     mov bx, di                                ; 89 fb
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 01f38h                          ; 75 4a
     mov dx, word [bp-018h]                    ; 8b 56 e8
     imul dx, ax                               ; 0f af d0
@@ -3701,7 +3701,7 @@ biosfn_write_char_only_:                     ; 0xc1e7a LB 0x16f
     movzx ax, byte [bp-012h]                  ; 0f b6 46 ee
     movzx bx, byte [bp-00eh]                  ; 0f b6 5e f2
     sal bx, 003h                              ; c1 e3 03
-    mov di, word [bx+04632h]                  ; 8b bf 32 46
+    mov di, word [bx+04633h]                  ; 8b bf 33 46
     mov bx, ax                                ; 89 c3
     mov dx, cx                                ; 89 ca
     mov ax, di                                ; 89 f8
@@ -3709,11 +3709,11 @@ biosfn_write_char_only_:                     ; 0xc1e7a LB 0x16f
     inc cx                                    ; 41
     inc cx                                    ; 41
     jmp short 01f14h                          ; eb dc
-    movzx di, byte [di+046aeh]                ; 0f b6 bd ae 46
+    movzx di, byte [di+046afh]                ; 0f b6 bd af 46
     sal di, 006h                              ; c1 e7 06
-    mov al, byte [di+046c4h]                  ; 8a 85 c4 46
+    mov al, byte [di+046c5h]                  ; 8a 85 c5 46
     mov byte [bp-00ah], al                    ; 88 46 f6
-    mov al, byte [bx+04631h]                  ; 8a 87 31 46
+    mov al, byte [bx+04632h]                  ; 8a 87 32 46
     mov byte [bp-008h], al                    ; 88 46 f8
     dec si                                    ; 4e
     cmp si, strict byte 0ffffh                ; 83 fe ff
@@ -3723,7 +3723,7 @@ biosfn_write_char_only_:                     ; 0xc1e7a LB 0x16f
     jnc near 01fe2h                           ; 0f 83 81 00
     movzx bx, byte [bp-00eh]                  ; 0f b6 5e f2
     sal bx, 003h                              ; c1 e3 03
-    mov bl, byte [bx+04630h]                  ; 8a 9f 30 46
+    mov bl, byte [bx+04631h]                  ; 8a 9f 31 46
     cmp bl, 003h                              ; 80 fb 03
     jc short 01f7fh                           ; 72 0e
     jbe short 01f86h                          ; 76 13
@@ -3786,9 +3786,9 @@ biosfn_write_pixel_:                         ; 0xc1fe9 LB 0x16a
     je near 0212bh                            ; 0f 84 1e 01
     movzx bx, al                              ; 0f b6 d8
     sal bx, 003h                              ; c1 e3 03
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     je near 0212bh                            ; 0f 84 0f 01
-    mov al, byte [bx+04630h]                  ; 8a 87 30 46
+    mov al, byte [bx+04631h]                  ; 8a 87 31 46
     cmp AL, strict byte 003h                  ; 3c 03
     jc short 02033h                           ; 72 0f
     jbe short 0203ah                          ; 76 14
@@ -3842,7 +3842,7 @@ biosfn_write_pixel_:                         ; 0xc1fe9 LB 0x16a
     mov ax, cx                                ; 89 c8
     shr ax, 1                                 ; d1 e8
     imul ax, ax, strict byte 00050h           ; 6b c0 50
-    cmp byte [bx+04631h], 002h                ; 80 bf 31 46 02
+    cmp byte [bx+04632h], 002h                ; 80 bf 32 46 02
     jne short 020b5h                          ; 75 08
     mov bx, word [bp-00ah]                    ; 8b 5e f6
     shr bx, 002h                              ; c1 eb 02
@@ -3860,7 +3860,7 @@ biosfn_write_pixel_:                         ; 0xc1fe9 LB 0x16a
     mov bl, al                                ; 88 c3
     movzx si, byte [bp-004h]                  ; 0f b6 76 fc
     sal si, 003h                              ; c1 e6 03
-    cmp byte [si+04631h], 002h                ; 80 bc 31 46 02
+    cmp byte [si+04632h], 002h                ; 80 bc 32 46 02
     jne short 020fbh                          ; 75 19
     mov al, byte [bp-00ah]                    ; 8a 46 f6
     and AL, strict byte 003h                  ; 24 03
@@ -3973,7 +3973,7 @@ biosfn_write_teletype_:                      ; 0xc2153 LB 0x241
     movzx bx, byte [bp-010h]                  ; 0f b6 5e f0
     mov si, bx                                ; 89 de
     sal si, 003h                              ; c1 e6 03
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 02256h                          ; 75 4d
     mov ax, word [bp-012h]                    ; 8b 46 ee
     imul ax, word [bp-014h]                   ; 0f af 46 ec
@@ -3990,7 +3990,7 @@ biosfn_write_teletype_:                      ; 0xc2153 LB 0x241
     add ax, ax                                ; 01 c0
     add cx, ax                                ; 01 c1
     movzx bx, byte [bp-00ch]                  ; 0f b6 5e f4
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov dx, cx                                ; 89 ca
     call 02f4ch                               ; e8 0f 0d
     cmp byte [bp-00eh], 003h                  ; 80 7e f2 03
@@ -3998,14 +3998,14 @@ biosfn_write_teletype_:                      ; 0xc2153 LB 0x241
     movzx bx, byte [bp-004h]                  ; 0f b6 5e fc
     mov dx, cx                                ; 89 ca
     inc dx                                    ; 42
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     call 02f4ch                               ; e8 f9 0c
     jmp near 022d4h                           ; e9 7e 00
-    movzx bx, byte [bx+046aeh]                ; 0f b6 9f ae 46
+    movzx bx, byte [bx+046afh]                ; 0f b6 9f af 46
     sal bx, 006h                              ; c1 e3 06
-    mov ah, byte [bx+046c4h]                  ; 8a a7 c4 46
-    mov dl, byte [si+04631h]                  ; 8a 94 31 46
-    mov al, byte [si+04630h]                  ; 8a 84 30 46
+    mov ah, byte [bx+046c5h]                  ; 8a a7 c5 46
+    mov dl, byte [si+04632h]                  ; 8a 94 32 46
+    mov al, byte [si+04631h]                  ; 8a 84 31 46
     cmp AL, strict byte 003h                  ; 3c 03
     jc short 0227ah                           ; 72 0c
     jbe short 02280h                          ; 76 10
@@ -4061,7 +4061,7 @@ biosfn_write_teletype_:                      ; 0xc2153 LB 0x241
     mov bl, byte [bp-012h]                    ; 8a 5e ee
     db  0feh, 0cbh
     ; dec bl                                    ; fe cb
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 02354h                          ; 75 4a
     mov ax, word [bp-012h]                    ; 8b 46 ee
     imul ax, word [bp-014h]                   ; 0f af 46 ec
@@ -4080,7 +4080,7 @@ biosfn_write_teletype_:                      ; 0xc2153 LB 0x241
     mov dx, cx                                ; 89 ca
     add dx, ax                                ; 01 c2
     inc dx                                    ; 42
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     call 02f3eh                               ; e8 02 0c
     push strict byte 00001h                   ; 6a 01
     movzx dx, byte [bp-006h]                  ; 0f b6 56 fa
@@ -4355,7 +4355,7 @@ biosfn_load_text_8_14_pat_:                  ; 0xc2538 LB 0x70
     mov di, bx                                ; 89 df
     sal di, 005h                              ; c1 e7 05
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 05bech                            ; 81 c6 ec 5b
+    add si, 05bedh                            ; 81 c6 ed 5b
     mov cx, strict word 0000eh                ; b9 0e 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -4411,7 +4411,7 @@ biosfn_load_text_8_8_pat_:                   ; 0xc25a8 LB 0x72
     mov di, bx                                ; 89 df
     sal di, 005h                              ; c1 e7 05
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 053ech                            ; 81 c6 ec 53
+    add si, 053edh                            ; 81 c6 ed 53
     mov cx, strict word 00008h                ; b9 08 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -4467,7 +4467,7 @@ biosfn_load_text_8_16_pat_:                  ; 0xc261a LB 0x72
     mov di, bx                                ; 89 df
     sal di, 005h                              ; c1 e7 05
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 069ech                            ; 81 c6 ec 69
+    add si, 069edh                            ; 81 c6 ed 69
     mov cx, strict word 00010h                ; b9 10 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -4601,7 +4601,7 @@ biosfn_read_state_info_:                     ; 0xc2752 LB 0x101
     push dx                                   ; 52
     push bx                                   ; 53
     mov cx, ds                                ; 8c d9
-    mov bx, 05382h                            ; bb 82 53
+    mov bx, 05383h                            ; bb 83 53
     mov dx, word [bp-00ah]                    ; 8b 56 f6
     mov ax, word [bp-008h]                    ; 8b 46 f8
     call 02f88h                               ; e8 20 08
@@ -5501,7 +5501,7 @@ find_vga_entry_:                             ; 0xc2f17 LB 0x27
     jnbe short 02f38h                         ; 77 0e
     movzx bx, al                              ; 0f b6 d8
     sal bx, 003h                              ; c1 e3 03
-    cmp dl, byte [bx+0462eh]                  ; 3a 97 2e 46
+    cmp dl, byte [bx+0462fh]                  ; 3a 97 2f 46
     jne short 02f24h                          ; 75 ee
     mov ah, al                                ; 88 c4
     mov al, ah                                ; 88 e0
@@ -6767,10 +6767,10 @@ vesa_pm_end:                                 ; 0xc4514 LB 0x1
   ; Padding 0xeb bytes at 0xc4515
   times 235 db 0
 
-section _DATA progbits vstart=0x4600 align=1 ; size=0x371e class=DATA group=DGROUP
-_msg_vga_init:                               ; 0xc4600 LB 0x2e
-    db  'Oracle VM VirtualBox Version 5.1.8 VGA BIOS', 00dh, 00ah, 000h
-_vga_modes:                                  ; 0xc462e LB 0x80
+section _DATA progbits vstart=0x4600 align=1 ; size=0x371f class=DATA group=DGROUP
+_msg_vga_init:                               ; 0xc4600 LB 0x2f
+    db  'Oracle VM VirtualBox Version 5.1.10 VGA BIOS', 00dh, 00ah, 000h
+_vga_modes:                                  ; 0xc462f LB 0x80
     db  000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
     db  002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
     db  004h, 001h, 002h, 002h, 000h, 0b8h, 0ffh, 001h, 005h, 001h, 002h, 002h, 000h, 0b8h, 0ffh, 001h
@@ -6779,11 +6779,11 @@ _vga_modes:                                  ; 0xc462e LB 0x80
     db  00fh, 001h, 003h, 001h, 000h, 0a0h, 0ffh, 000h, 010h, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
     db  011h, 001h, 003h, 001h, 000h, 0a0h, 0ffh, 002h, 012h, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
     db  013h, 001h, 005h, 008h, 000h, 0a0h, 0ffh, 003h, 06ah, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
-_line_to_vpti:                               ; 0xc46ae LB 0x10
+_line_to_vpti:                               ; 0xc46af LB 0x10
     db  017h, 017h, 018h, 018h, 004h, 005h, 006h, 007h, 00dh, 00eh, 011h, 012h, 01ah, 01bh, 01ch, 01dh
-_dac_regs:                                   ; 0xc46be LB 0x4
+_dac_regs:                                   ; 0xc46bf LB 0x4
     dd  0ff3f3f3fh
-_video_param_table:                          ; 0xc46c2 LB 0x780
+_video_param_table:                          ; 0xc46c3 LB 0x780
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
@@ -6904,7 +6904,7 @@ _video_param_table:                          ; 0xc46c2 LB 0x780
     db  072h, 0f0h, 000h, 060h, 000h, 000h, 000h, 000h, 000h, 000h, 059h, 08dh, 057h, 032h, 000h, 057h
     db  073h, 0e3h, 0ffh, 000h, 001h, 002h, 003h, 004h, 005h, 014h, 007h, 038h, 039h, 03ah, 03bh, 03ch
     db  03dh, 03eh, 03fh, 001h, 000h, 00fh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 005h, 00fh, 0ffh
-_palette0:                                   ; 0xc4e42 LB 0xc0
+_palette0:                                   ; 0xc4e43 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
@@ -6917,7 +6917,7 @@ _palette0:                                   ; 0xc4e42 LB 0xc0
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
     db  03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
-_palette1:                                   ; 0xc4f02 LB 0xc0
+_palette1:                                   ; 0xc4f03 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah
     db  000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah, 000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah
@@ -6930,7 +6930,7 @@ _palette1:                                   ; 0xc4f02 LB 0xc0
     db  015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh, 015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh
     db  015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
-_palette2:                                   ; 0xc4fc2 LB 0xc0
+_palette2:                                   ; 0xc4fc3 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 02ah, 000h, 02ah, 02ah, 02ah, 000h, 000h, 015h, 000h, 000h, 03fh, 000h, 02ah
     db  015h, 000h, 02ah, 03fh, 02ah, 000h, 015h, 02ah, 000h, 03fh, 02ah, 02ah, 015h, 02ah, 02ah, 03fh
@@ -6943,7 +6943,7 @@ _palette2:                                   ; 0xc4fc2 LB 0xc0
     db  015h, 015h, 000h, 015h, 015h, 02ah, 015h, 03fh, 000h, 015h, 03fh, 02ah, 03fh, 015h, 000h, 03fh
     db  015h, 02ah, 03fh, 03fh, 000h, 03fh, 03fh, 02ah, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
-_palette3:                                   ; 0xc5082 LB 0x300
+_palette3:                                   ; 0xc5083 LB 0x300
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
@@ -6992,19 +6992,19 @@ _palette3:                                   ; 0xc5082 LB 0x300
     db  00bh, 010h, 00bh, 00bh, 010h, 00ch, 00bh, 010h, 00dh, 00bh, 010h, 00fh, 00bh, 010h, 010h, 00bh
     db  00fh, 010h, 00bh, 00dh, 010h, 00bh, 00ch, 010h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_static_functionality:                       ; 0xc5382 LB 0x10
+_static_functionality:                       ; 0xc5383 LB 0x10
     db  0ffh, 0e0h, 00fh, 000h, 000h, 000h, 000h, 007h, 002h, 008h, 0e7h, 00ch, 000h, 000h, 000h, 000h
-_dcc_table:                                  ; 0xc5392 LB 0x24
+_dcc_table:                                  ; 0xc5393 LB 0x24
     db  010h, 001h, 007h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h
-_secondary_save_area:                        ; 0xc53b6 LB 0x1a
-    db  01ah, 000h, 092h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+_secondary_save_area:                        ; 0xc53b7 LB 0x1a
+    db  01ah, 000h, 093h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_video_save_pointer_table:                   ; 0xc53d0 LB 0x1c
-    db  0c2h, 046h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  0b6h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont8:                                   ; 0xc53ec LB 0x800
+_video_save_pointer_table:                   ; 0xc53d1 LB 0x1c
+    db  0c3h, 046h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+    db  0b7h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+_vgafont8:                                   ; 0xc53ed LB 0x800
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07eh, 081h, 0a5h, 081h, 0bdh, 099h, 081h, 07eh
     db  07eh, 0ffh, 0dbh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh, 06ch, 0feh, 0feh, 0feh, 07ch, 038h, 010h, 000h
     db  010h, 038h, 07ch, 0feh, 07ch, 038h, 010h, 000h, 038h, 07ch, 038h, 0feh, 0feh, 07ch, 038h, 07ch
@@ -7133,7 +7133,7 @@ _vgafont8:                                   ; 0xc53ec LB 0x800
     db  000h, 000h, 000h, 000h, 018h, 000h, 000h, 000h, 00fh, 00ch, 00ch, 00ch, 0ech, 06ch, 03ch, 01ch
     db  078h, 06ch, 06ch, 06ch, 06ch, 000h, 000h, 000h, 070h, 018h, 030h, 060h, 078h, 000h, 000h, 000h
     db  000h, 000h, 03ch, 03ch, 03ch, 03ch, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont14:                                  ; 0xc5bec LB 0xe00
+_vgafont14:                                  ; 0xc5bed LB 0xe00
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  07eh, 081h, 0a5h, 081h, 081h, 0bdh, 099h, 081h, 07eh, 000h, 000h, 000h, 000h, 000h, 07eh, 0ffh
     db  0dbh, 0ffh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh, 000h, 000h, 000h, 000h, 000h, 000h, 06ch, 0feh, 0feh
@@ -7358,7 +7358,7 @@ _vgafont14:                                  ; 0xc5bec LB 0xe00
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 070h, 0d8h, 030h, 060h, 0c8h, 0f8h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont16:                                  ; 0xc69ec LB 0x1000
+_vgafont16:                                  ; 0xc69ed LB 0x1000
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 07eh, 081h, 0a5h, 081h, 081h, 0bdh, 099h, 081h, 081h, 07eh, 000h, 000h, 000h, 000h
     db  000h, 000h, 07eh, 0ffh, 0dbh, 0ffh, 0ffh, 0c3h, 0e7h, 0ffh, 0ffh, 07eh, 000h, 000h, 000h, 000h
@@ -7615,7 +7615,7 @@ _vgafont16:                                  ; 0xc69ec LB 0x1000
     db  000h, 070h, 0d8h, 030h, 060h, 0c8h, 0f8h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont14alt:                               ; 0xc79ec LB 0x12d
+_vgafont14alt:                               ; 0xc79ed LB 0x12d
     db  01dh, 000h, 000h, 000h, 000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h, 000h, 000h, 000h, 022h
     db  000h, 063h, 063h, 063h, 022h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 02bh, 000h
     db  000h, 000h, 018h, 018h, 018h, 0ffh, 018h, 018h, 018h, 000h, 000h, 000h, 000h, 02dh, 000h, 000h
@@ -7635,7 +7635,7 @@ _vgafont14alt:                               ; 0xc79ec LB 0x12d
     db  000h, 0fch, 066h, 066h, 07ch, 062h, 066h, 06fh, 066h, 066h, 0f3h, 000h, 000h, 000h, 0f1h, 000h
     db  000h, 018h, 018h, 018h, 0ffh, 018h, 018h, 018h, 000h, 0ffh, 000h, 000h, 000h, 0f6h, 000h, 000h
     db  018h, 018h, 000h, 000h, 0ffh, 000h, 000h, 018h, 018h, 000h, 000h, 000h, 000h
-_vgafont16alt:                               ; 0xc7b19 LB 0x145
+_vgafont16alt:                               ; 0xc7b1a LB 0x144
     db  01dh, 000h, 000h, 000h, 000h, 000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h, 000h, 000h, 000h
     db  000h, 030h, 000h, 000h, 03ch, 066h, 0c3h, 0c3h, 0dbh, 0dbh, 0c3h, 0c3h, 066h, 03ch, 000h, 000h
     db  000h, 000h, 04dh, 000h, 000h, 0c3h, 0e7h, 0ffh, 0ffh, 0dbh, 0c3h, 0c3h, 0c3h, 0c3h, 0c3h, 000h
@@ -7656,32 +7656,34 @@ _vgafont16alt:                               ; 0xc7b19 LB 0x145
     db  09eh, 000h, 0fch, 066h, 066h, 07ch, 062h, 066h, 06fh, 066h, 066h, 066h, 0f3h, 000h, 000h, 000h
     db  000h, 0abh, 000h, 0c0h, 0c0h, 0c2h, 0c6h, 0cch, 018h, 030h, 060h, 0ceh, 09bh, 006h, 00ch, 01fh
     db  000h, 000h, 0ach, 000h, 0c0h, 0c0h, 0c2h, 0c6h, 0cch, 018h, 030h, 066h, 0ceh, 096h, 03eh, 006h
-    db  006h, 000h, 000h, 000h, 000h
+    db  006h, 000h, 000h, 000h
 _vbebios_copyright:                          ; 0xc7c5e LB 0x15
     db  'VirtualBox VESA BIOS', 000h
 _vbebios_vendor_name:                        ; 0xc7c73 LB 0x13
     db  'Oracle Corporation', 000h
 _vbebios_product_name:                       ; 0xc7c86 LB 0x21
     db  'Oracle VM VirtualBox VBE Adapter', 000h
-_vbebios_product_revision:                   ; 0xc7ca7 LB 0x23
-    db  'Oracle VM VirtualBox Version 5.1.8', 000h
-_vbebios_info_string:                        ; 0xc7cca LB 0x2b
+_vbebios_product_revision:                   ; 0xc7ca7 LB 0x24
+    db  'Oracle VM VirtualBox Version 5.1.10', 000h
+_vbebios_info_string:                        ; 0xc7ccb LB 0x2b
     db  'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
-_no_vbebios_info_string:                     ; 0xc7cf5 LB 0x29
+_no_vbebios_info_string:                     ; 0xc7cf6 LB 0x29
     db  'No VirtualBox VBE support available!', 00dh, 00ah, 00dh, 00ah, 000h
 
-section CONST progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
+  ; Padding 0x1 bytes at 0xc7d1f
+    db  001h
 
-section CONST2 progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
+section CONST progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
 
-  ; Padding 0x2e2 bytes at 0xc7d1e
-    db  001h, 000h, 000h, 000h, 000h, 001h, 000h, 000h, 000h, 000h, 000h, 000h, 02fh, 068h, 06fh, 06dh
-    db  065h, 02fh, 066h, 06dh, 033h, 02fh, 073h, 072h, 063h, 02fh, 076h, 062h, 06fh, 078h, 02dh, 035h
-    db  02eh, 031h, 02fh, 06fh, 075h, 074h, 02fh, 06ch, 069h, 06eh, 075h, 078h, 02eh, 061h, 06dh, 064h
-    db  036h, 034h, 02fh, 072h, 065h, 06ch, 065h, 061h, 073h, 065h, 02fh, 06fh, 062h, 06ah, 02fh, 056h
-    db  042h, 06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 033h, 038h, 036h, 02fh, 056h, 042h
-    db  06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 033h, 038h, 036h, 02eh, 073h, 079h, 06dh
-    db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+section CONST2 progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
+
+  ; Padding 0x2e0 bytes at 0xc7d20
+    db  000h, 000h, 000h, 000h, 001h, 000h, 000h, 000h, 000h, 000h, 000h, 02fh, 068h, 06fh, 06dh, 065h
+    db  02fh, 066h, 06dh, 033h, 02fh, 073h, 072h, 063h, 02fh, 076h, 062h, 06fh, 078h, 02dh, 035h, 02eh
+    db  031h, 02fh, 06fh, 075h, 074h, 02fh, 06ch, 069h, 06eh, 075h, 078h, 02eh, 061h, 06dh, 064h, 036h
+    db  034h, 02fh, 072h, 065h, 06ch, 065h, 061h, 073h, 065h, 02fh, 06fh, 062h, 06ah, 02fh, 056h, 042h
+    db  06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 033h, 038h, 036h, 02fh, 056h, 042h, 06fh
+    db  078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 033h, 038h, 036h, 02eh, 073h, 079h, 06dh, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
@@ -7721,4 +7723,4 @@ section CONST2 progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  000h, 06dh
+    db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0bdh
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
index 9c41032..dfb1818 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
@@ -1 +1 @@
-6500e14d937eefc731fa76c7b1d69bb8 *VBoxVgaBios386.rom
+9ec2d097efbeb1716a38d602638dafa9 *VBoxVgaBios386.rom
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
index 7ef5e8b..db76341 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
@@ -1741,7 +1741,7 @@ vga_read_char_attr_:                         ; 0xc0ad2 LB 0xaf
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 00b68h                          ; 75 2e
     mul word [bp-00ch]                        ; f7 66 f4
     sal ax, 1                                 ; d1 e0
@@ -1760,7 +1760,7 @@ vga_read_char_attr_:                         ; 0xc0ad2 LB 0xaf
     add dx, ax                                ; 01 c2
     sal dx, 1                                 ; d1 e2
     add dx, cx                                ; 01 ca
-    mov ax, word [bx+04632h]                  ; 8b 87 32 46
+    mov ax, word [bx+04633h]                  ; 8b 87 33 46
     call 031b7h                               ; e8 52 26
     mov word [ss:si], ax                      ; 36 89 04
     lea sp, [bp-008h]                         ; 8d 66 f8
@@ -1827,18 +1827,18 @@ vga_get_font_info_:                          ; 0xc0b81 LB 0x7b
     retn 00002h                               ; c2 02 00
     mov dx, 0010ch                            ; ba 0c 01
     jmp short 00b99h                          ; eb c0
-    mov ax, 05bech                            ; b8 ec 5b
+    mov ax, 05bedh                            ; b8 ed 5b
     mov dx, 0c000h                            ; ba 00 c0
     jmp short 00b9eh                          ; eb bd
-    mov ax, 053ech                            ; b8 ec 53
+    mov ax, 053edh                            ; b8 ed 53
     jmp short 00bdch                          ; eb f6
-    mov ax, 057ech                            ; b8 ec 57
+    mov ax, 057edh                            ; b8 ed 57
     jmp short 00bdch                          ; eb f1
-    mov ax, 079ech                            ; b8 ec 79
+    mov ax, 079edh                            ; b8 ed 79
     jmp short 00bdch                          ; eb ec
-    mov ax, 069ech                            ; b8 ec 69
+    mov ax, 069edh                            ; b8 ed 69
     jmp short 00bdch                          ; eb e7
-    mov ax, 07b19h                            ; b8 19 7b
+    mov ax, 07b1ah                            ; b8 1a 7b
     jmp short 00bdch                          ; eb e2
     jmp short 00bcbh                          ; eb cf
 vga_read_pixel_:                             ; 0xc0bfc LB 0x143
@@ -1862,10 +1862,10 @@ vga_read_pixel_:                             ; 0xc0bfc LB 0x143
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 00c31h                          ; 75 03
     jmp near 00d38h                           ; e9 07 01
-    mov bl, byte [bx+04630h]                  ; 8a 9f 30 46
+    mov bl, byte [bx+04631h]                  ; 8a 9f 31 46
     cmp bl, cl                                ; 38 cb
     jc short 00c48h                           ; 72 0f
     jbe short 00c50h                          ; 76 15
@@ -1933,7 +1933,7 @@ vga_read_pixel_:                             ; 0xc0bfc LB 0x143
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+04631h], 002h                ; 80 bf 31 46 02
+    cmp byte [bx+04632h], 002h                ; 80 bf 32 46 02
     jne short 00cfah                          ; 75 1b
     mov cx, si                                ; 89 f1
     xor ch, ch                                ; 30 ed
@@ -2267,7 +2267,7 @@ biosfn_set_active_page_:                     ; 0xc0f34 LB 0xe5
     mov CL, strict byte 003h                  ; b1 03
     mov si, bx                                ; 89 de
     sal si, CL                                ; d3 e6
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 00fc0h                          ; 75 47
     mov dx, strict word 0004ah                ; ba 4a 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2299,12 +2299,12 @@ biosfn_set_active_page_:                     ; 0xc0f34 LB 0xe5
     lea ax, [si+001h]                         ; 8d 44 01
     mul di                                    ; f7 e7
     jmp short 00fd0h                          ; eb 10
-    mov bl, byte [bx+046aeh]                  ; 8a 9f ae 46
+    mov bl, byte [bx+046afh]                  ; 8a 9f af 46
     mov CL, strict byte 006h                  ; b1 06
     sal bx, CL                                ; d3 e3
     mov al, ch                                ; 88 e8
     xor ah, ah                                ; 30 e4
-    mul word [bx+046c5h]                      ; f7 a7 c5 46
+    mul word [bx+046c6h]                      ; f7 a7 c6 46
     mov bx, ax                                ; 89 c3
     mov dx, strict word 00063h                ; ba 63 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2377,18 +2377,18 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov byte [bp-014h], al                    ; 88 46 ec
     mov byte [bp-013h], 000h                  ; c6 46 ed 00
     mov bx, word [bp-014h]                    ; 8b 5e ec
-    mov al, byte [bx+046aeh]                  ; 8a 87 ae 46
+    mov al, byte [bx+046afh]                  ; 8a 87 af 46
     mov byte [bp-00eh], al                    ; 88 46 f2
     mov bl, al                                ; 88 c3
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 006h                  ; b1 06
     sal bx, CL                                ; d3 e3
-    mov al, byte [bx+046c2h]                  ; 8a 87 c2 46
+    mov al, byte [bx+046c3h]                  ; 8a 87 c3 46
     xor ah, ah                                ; 30 e4
     mov word [bp-016h], ax                    ; 89 46 ea
-    mov al, byte [bx+046c3h]                  ; 8a 87 c3 46
-    mov word [bp-018h], ax                    ; 89 46 e8
     mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
+    mov word [bp-018h], ax                    ; 89 46 e8
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
     mov word [bp-01ah], ax                    ; 89 46 e6
     mov dx, 00087h                            ; ba 87 00
     mov ax, strict word 00040h                ; b8 40 00
@@ -2405,13 +2405,13 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov CL, strict byte 003h                  ; b1 03
     mov bx, word [bp-014h]                    ; 8b 5e ec
     sal bx, CL                                ; d3 e3
-    mov al, byte [bx+04634h]                  ; 8a 87 34 46
+    mov al, byte [bx+04635h]                  ; 8a 87 35 46
     mov dx, 003c6h                            ; ba c6 03
     out DX, AL                                ; ee
     xor al, al                                ; 30 c0
     mov dx, 003c8h                            ; ba c8 03
     out DX, AL                                ; ee
-    mov bl, byte [bx+04635h]                  ; 8a 9f 35 46
+    mov bl, byte [bx+04636h]                  ; 8a 9f 36 46
     cmp bl, 001h                              ; 80 fb 01
     jc short 010dbh                           ; 72 0d
     jbe short 010e4h                          ; 76 14
@@ -2422,13 +2422,13 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     jmp short 010f1h                          ; eb 16
     test bl, bl                               ; 84 db
     jne short 010f1h                          ; 75 12
-    mov di, 04e42h                            ; bf 42 4e
+    mov di, 04e43h                            ; bf 43 4e
     jmp short 010f1h                          ; eb 0d
-    mov di, 04f02h                            ; bf 02 4f
+    mov di, 04f03h                            ; bf 03 4f
     jmp short 010f1h                          ; eb 08
-    mov di, 04fc2h                            ; bf c2 4f
+    mov di, 04fc3h                            ; bf c3 4f
     jmp short 010f1h                          ; eb 03
-    mov di, 05082h                            ; bf 82 50
+    mov di, 05083h                            ; bf 83 50
     xor bx, bx                                ; 31 db
     jmp short 010fdh                          ; eb 08
     jmp short 01149h                          ; eb 52
@@ -2439,9 +2439,9 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov CL, strict byte 003h                  ; b1 03
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    mov al, byte [si+04635h]                  ; 8a 84 35 46
+    mov al, byte [si+04636h]                  ; 8a 84 36 46
     mov si, ax                                ; 89 c6
-    mov al, byte [si+046beh]                  ; 8a 84 be 46
+    mov al, byte [si+046bfh]                  ; 8a 84 bf 46
     cmp bx, ax                                ; 39 c3
     jnbe short 01131h                         ; 77 1b
     mov ax, bx                                ; 89 d8
@@ -2486,7 +2486,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
     add si, bx                                ; 01 de
-    mov al, byte [si+046e5h]                  ; 8a 84 e5 46
+    mov al, byte [si+046e6h]                  ; 8a 84 e6 46
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 01153h                          ; eb e0
@@ -2513,7 +2513,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
     add si, bx                                ; 01 de
-    mov al, byte [si+046c6h]                  ; 8a 84 c6 46
+    mov al, byte [si+046c7h]                  ; 8a 84 c7 46
     mov dx, 003c5h                            ; ba c5 03
     out DX, AL                                ; ee
     inc bx                                    ; 43
@@ -2531,7 +2531,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
     add si, bx                                ; 01 de
-    mov al, byte [si+046f9h]                  ; 8a 84 f9 46
+    mov al, byte [si+046fah]                  ; 8a 84 fa 46
     mov dx, 003cfh                            ; ba cf 03
     out DX, AL                                ; ee
     inc bx                                    ; 43
@@ -2540,7 +2540,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+04630h], 001h                ; 80 bf 30 46 01
+    cmp byte [bx+04631h], 001h                ; 80 bf 31 46 01
     jne short 011eah                          ; 75 05
     mov dx, 003b4h                            ; ba b4 03
     jmp short 011edh                          ; eb 03
@@ -2563,12 +2563,12 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov di, ax                                ; 89 c7
     add di, bx                                ; 01 df
     lea dx, [si+001h]                         ; 8d 54 01
-    mov al, byte [di+046cch]                  ; 8a 85 cc 46
+    mov al, byte [di+046cdh]                  ; 8a 85 cd 46
     out DX, AL                                ; ee
     inc bx                                    ; 43
     jmp short 011f7h                          ; eb dc
     mov bx, cx                                ; 89 cb
-    mov al, byte [bx+046cbh]                  ; 8a 87 cb 46
+    mov al, byte [bx+046cch]                  ; 8a 87 cc 46
     mov dx, 003c2h                            ; ba c2 03
     out DX, AL                                ; ee
     mov AL, strict byte 020h                  ; b0 20
@@ -2584,9 +2584,9 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     xor bh, ch                                ; 30 ef
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 0125ah                          ; 75 13
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 04000h                            ; b9 00 40
     mov ax, 00720h                            ; b8 20 07
     xor di, di                                ; 31 ff
@@ -2596,7 +2596,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     jmp short 01298h                          ; eb 3e
     cmp byte [bp-00ch], 00dh                  ; 80 7e f4 0d
     jnc short 01272h                          ; 73 12
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 04000h                            ; b9 00 40
     xor ax, ax                                ; 31 c0
     xor di, di                                ; 31 ff
@@ -2614,7 +2614,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov word [bp-01ch], ax                    ; 89 46 e4
     mov AL, strict byte 00fh                  ; b0 0f
     out DX, AL                                ; ee
-    mov es, [bx+04632h]                       ; 8e 87 32 46
+    mov es, [bx+04633h]                       ; 8e 87 33 46
     mov cx, 08000h                            ; b9 00 80
     xor ax, ax                                ; 31 c0
     xor di, di                                ; 31 ff
@@ -2636,7 +2636,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 006h                  ; b1 06
     sal bx, CL                                ; d3 e3
-    mov bx, word [bx+046c5h]                  ; 8b 9f c5 46
+    mov bx, word [bx+046c6h]                  ; 8b 9f c6 46
     mov dx, strict word 0004ch                ; ba 4c 00
     mov ax, strict word 00040h                ; b8 40 00
     call 031c5h                               ; e8 fd 1e
@@ -2677,7 +2677,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov ax, strict word 00040h                ; b8 40 00
     call 031a9h                               ; e8 7a 1e
     mov cx, ds                                ; 8c d9
-    mov bx, 053d0h                            ; bb d0 53
+    mov bx, 053d1h                            ; bb d1 53
     mov dx, 000a8h                            ; ba a8 00
     mov ax, strict word 00040h                ; b8 40 00
     call 031e5h                               ; e8 a8 1e
@@ -2693,7 +2693,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 0136ch                          ; 75 09
     mov dx, strict word 00007h                ; ba 07 00
     mov ax, strict word 00006h                ; b8 06 00
@@ -2714,7 +2714,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 013a6h                          ; 75 10
     xor bl, bl                                ; 30 db
     mov AL, strict byte 004h                  ; b0 04
@@ -2724,7 +2724,7 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     mov al, cl                                ; 88 c8
     mov AH, strict byte 011h                  ; b4 11
     int 010h                                  ; cd 10
-    mov dx, 057ech                            ; ba ec 57
+    mov dx, 057edh                            ; ba ed 57
     mov ax, strict word 0001fh                ; b8 1f 00
     call 00a00h                               ; e8 51 f6
     mov ax, word [bp-01ah]                    ; 8b 46 e6
@@ -2734,13 +2734,13 @@ biosfn_set_video_mode_:                      ; 0xc1019 LB 0x3c7
     je short 013cch                           ; 74 10
     cmp ax, strict word 00008h                ; 3d 08 00
     jne short 013d6h                          ; 75 15
-    mov dx, 053ech                            ; ba ec 53
+    mov dx, 053edh                            ; ba ed 53
     mov ax, strict word 00043h                ; b8 43 00
     call 00a00h                               ; e8 36 f6
     jmp short 013d6h                          ; eb 0a
-    mov dx, 05bech                            ; ba ec 5b
+    mov dx, 05bedh                            ; ba ed 5b
     jmp short 013c4h                          ; eb f3
-    mov dx, 069ech                            ; ba ec 69
+    mov dx, 069edh                            ; ba ed 69
     jmp short 013c4h                          ; eb ee
     lea sp, [bp-00ah]                         ; 8d 66 f6
     pop di                                    ; 5f
@@ -3129,7 +3129,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mov ax, word [bp-018h]                    ; 8b 46 e8
     mul bx                                    ; f7 e3
     mov word [bp-01ah], ax                    ; 89 46 e6
-    cmp byte [di+0462fh], 000h                ; 80 bd 2f 46 00
+    cmp byte [di+04630h], 000h                ; 80 bd 30 46 00
     jne short 01766h                          ; 75 50
     sal ax, 1                                 ; d1 e0
     or AL, strict byte 0ffh                   ; 0c ff
@@ -3156,7 +3156,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mov ah, byte [bp-008h]                    ; 8a 66 f8
     xor al, ch                                ; 30 e8
     add ax, strict word 00020h                ; 05 20 00
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, word [bp-01ah]                    ; 8b 4e e6
     mov di, bx                                ; 89 df
     cld                                       ; fc
@@ -3201,7 +3201,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mov CL, strict byte 003h                  ; b1 03
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    mov es, [si+04632h]                       ; 8e 84 32 46
+    mov es, [si+04633h]                       ; 8e 84 33 46
     mov cx, word [bp-022h]                    ; 8b 4e de
     mov ax, di                                ; 89 f8
     mov di, dx                                ; 89 d7
@@ -3225,7 +3225,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mov CL, strict byte 003h                  ; b1 03
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov word [bp-022h], ax                    ; 89 46 de
     mov ax, word [bp-016h]                    ; 8b 46 ea
     mul word [bp-018h]                        ; f7 66 e8
@@ -3277,7 +3277,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mov CL, strict byte 003h                  ; b1 03
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    mov si, word [si+04632h]                  ; 8b b4 32 46
+    mov si, word [si+04633h]                  ; 8b b4 33 46
     mov cx, di                                ; 89 f9
     mov ax, word [bp-022h]                    ; 8b 46 de
     mov di, dx                                ; 89 d7
@@ -3305,7 +3305,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mov CL, strict byte 003h                  ; b1 03
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov word [bp-014h], ax                    ; 89 46 ec
     mov ax, word [bp-016h]                    ; 8b 46 ea
     mul word [bp-018h]                        ; f7 66 e8
@@ -3329,14 +3329,14 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     jc short 0191ah                           ; 72 29
     dec word [bp-016h]                        ; ff 4e ea
     jmp near 01835h                           ; e9 3e ff
-    mov al, byte [si+046aeh]                  ; 8a 84 ae 46
+    mov al, byte [si+046afh]                  ; 8a 84 af 46
     xor ah, ah                                ; 30 e4
     mov CL, strict byte 006h                  ; b1 06
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    mov al, byte [si+046c4h]                  ; 8a 84 c4 46
+    mov al, byte [si+046c5h]                  ; 8a 84 c5 46
     mov byte [bp-012h], al                    ; 88 46 ee
-    mov al, byte [di+04630h]                  ; 8a 85 30 46
+    mov al, byte [di+04631h]                  ; 8a 85 31 46
     cmp AL, strict byte 004h                  ; 3c 04
     je short 0191dh                           ; 74 0b
     cmp AL, strict byte 003h                  ; 3c 03
@@ -3378,7 +3378,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    mov bx, word [bx+04632h]                  ; 8b 9f 32 46
+    mov bx, word [bx+04633h]                  ; 8b 9f 33 46
     mov cx, ax                                ; 89 c1
     mov ax, dx                                ; 89 d0
     xor di, di                                ; 31 ff
@@ -3492,7 +3492,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     jc short 01acch                           ; 72 4c
     dec word [bp-016h]                        ; ff 4e ea
     jmp short 01a10h                          ; eb 8b
-    mov bl, byte [di+04631h]                  ; 8a 9d 31 46
+    mov bl, byte [di+04632h]                  ; 8a 9d 32 46
     cmp byte [bp-00ah], 000h                  ; 80 7e f6 00
     jne short 01acfh                          ; 75 40
     cmp byte [bp-00eh], 000h                  ; 80 7e f2 00
@@ -3513,7 +3513,7 @@ biosfn_scroll_:                              ; 0xc1655 LB 0x576
     mul bx                                    ; f7 e3
     mov dl, byte [bp-008h]                    ; 8a 56 f8
     xor dh, dh                                ; 30 f6
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, ax                                ; 89 c1
     mov ax, dx                                ; 89 d0
     xor di, di                                ; 31 ff
@@ -3638,11 +3638,11 @@ write_gfx_char_pl4_:                         ; 0xc1bcb LB 0xf8
     je short 01befh                           ; 74 0b
     cmp byte [bp+006h], 00eh                  ; 80 7e 06 0e
     jne short 01bf4h                          ; 75 0a
-    mov di, 05bech                            ; bf ec 5b
+    mov di, 05bedh                            ; bf ed 5b
     jmp short 01bf7h                          ; eb 08
-    mov di, 069ech                            ; bf ec 69
+    mov di, 069edh                            ; bf ed 69
     jmp short 01bf7h                          ; eb 03
-    mov di, 053ech                            ; bf ec 53
+    mov di, 053edh                            ; bf ed 53
     xor ah, ah                                ; 30 e4
     mov bx, ax                                ; 89 c3
     mov al, byte [bp+006h]                    ; 8a 46 06
@@ -3740,7 +3740,7 @@ write_gfx_char_cga_:                         ; 0xc1cc3 LB 0x13a
     sub sp, strict byte 0000ah                ; 83 ec 0a
     mov byte [bp-008h], al                    ; 88 46 f8
     mov byte [bp-00ah], dl                    ; 88 56 f6
-    mov si, 053ech                            ; be ec 53
+    mov si, 053edh                            ; be ed 53
     xor bh, bh                                ; 30 ff
     mov al, byte [bp+006h]                    ; 8a 46 06
     xor ah, ah                                ; 30 e4
@@ -3878,7 +3878,7 @@ write_gfx_char_lin_:                         ; 0xc1dfd LB 0xac
     mov byte [bp-00ch], dl                    ; 88 56 f4
     mov byte [bp-006h], bl                    ; 88 5e fa
     mov al, cl                                ; 88 c8
-    mov si, 053ech                            ; be ec 53
+    mov si, 053edh                            ; be ed 53
     xor ah, ah                                ; 30 e4
     mov bl, byte [bp+004h]                    ; 8a 5e 04
     xor bh, bh                                ; 30 ff
@@ -3993,7 +3993,7 @@ biosfn_write_char_attr_:                     ; 0xc1ea9 LB 0x192
     mov CL, strict byte 003h                  ; b1 03
     mov di, ax                                ; 89 c7
     sal di, CL                                ; d3 e7
-    cmp byte [di+0462fh], 000h                ; 80 bd 2f 46 00
+    cmp byte [di+04630h], 000h                ; 80 bd 30 46 00
     jne short 01f67h                          ; 75 49
     mov ax, bx                                ; 89 d8
     mul word [bp-01ah]                        ; f7 66 e6
@@ -4020,7 +4020,7 @@ biosfn_write_char_attr_:                     ; 0xc1ea9 LB 0x192
     mov bl, byte [bp-008h]                    ; 8a 5e f8
     mov word [bp-01ch], bx                    ; 89 5e e4
     mov ax, word [bp-01ch]                    ; 8b 46 e4
-    mov es, [di+04632h]                       ; 8e 85 32 46
+    mov es, [di+04633h]                       ; 8e 85 33 46
     mov cx, si                                ; 89 f1
     mov di, dx                                ; 89 d7
     cld                                       ; fc
@@ -4028,13 +4028,13 @@ biosfn_write_char_attr_:                     ; 0xc1ea9 LB 0x192
     rep stosw                                 ; f3 ab
     jmp near 02034h                           ; e9 cd 00
     mov bx, ax                                ; 89 c3
-    mov al, byte [bx+046aeh]                  ; 8a 87 ae 46
+    mov al, byte [bx+046afh]                  ; 8a 87 af 46
     mov CL, strict byte 006h                  ; b1 06
     mov bx, ax                                ; 89 c3
     sal bx, CL                                ; d3 e3
-    mov al, byte [bx+046c4h]                  ; 8a 87 c4 46
+    mov al, byte [bx+046c5h]                  ; 8a 87 c5 46
     mov byte [bp-010h], al                    ; 88 46 f0
-    mov al, byte [di+04631h]                  ; 8a 85 31 46
+    mov al, byte [di+04632h]                  ; 8a 85 32 46
     mov byte [bp-00ah], al                    ; 88 46 f6
     dec si                                    ; 4e
     cmp si, strict byte 0ffffh                ; 83 fe ff
@@ -4048,7 +4048,7 @@ biosfn_write_char_attr_:                     ; 0xc1ea9 LB 0x192
     mov CL, strict byte 003h                  ; b1 03
     mov bx, ax                                ; 89 c3
     sal bx, CL                                ; d3 e3
-    mov al, byte [bx+04630h]                  ; 8a 87 30 46
+    mov al, byte [bx+04631h]                  ; 8a 87 31 46
     cmp al, cl                                ; 38 c8
     jc short 01fb2h                           ; 72 0d
     jbe short 01fb8h                          ; 76 11
@@ -4164,7 +4164,7 @@ biosfn_write_char_only_:                     ; 0xc203b LB 0x193
     mov ax, bx                                ; 89 d8
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     jne short 02102h                          ; 75 4e
     mov ax, di                                ; 89 f8
     mul word [bp-018h]                        ; f7 66 e8
@@ -4194,7 +4194,7 @@ biosfn_write_char_only_:                     ; 0xc203b LB 0x193
     mov CL, strict byte 003h                  ; b1 03
     mov bx, dx                                ; 89 d3
     sal bx, CL                                ; d3 e3
-    mov cx, word [bx+04632h]                  ; 8b 8f 32 46
+    mov cx, word [bx+04633h]                  ; 8b 8f 33 46
     mov bx, ax                                ; 89 c3
     mov dx, di                                ; 89 fa
     mov ax, cx                                ; 89 c8
@@ -4203,14 +4203,14 @@ biosfn_write_char_only_:                     ; 0xc203b LB 0x193
     inc di                                    ; 47
     jmp short 020dbh                          ; eb d9
     mov di, ax                                ; 89 c7
-    mov dl, byte [di+046aeh]                  ; 8a 95 ae 46
+    mov dl, byte [di+046afh]                  ; 8a 95 af 46
     xor dh, dh                                ; 30 f6
     mov CL, strict byte 006h                  ; b1 06
     mov di, dx                                ; 89 d7
     sal di, CL                                ; d3 e7
-    mov al, byte [di+046c4h]                  ; 8a 85 c4 46
+    mov al, byte [di+046c5h]                  ; 8a 85 c5 46
     mov byte [bp-012h], al                    ; 88 46 ee
-    mov al, byte [bx+04631h]                  ; 8a 87 31 46
+    mov al, byte [bx+04632h]                  ; 8a 87 32 46
     mov byte [bp-010h], al                    ; 88 46 f0
     dec si                                    ; 4e
     cmp si, strict byte 0ffffh                ; 83 fe ff
@@ -4223,7 +4223,7 @@ biosfn_write_char_only_:                     ; 0xc203b LB 0x193
     mov CL, strict byte 003h                  ; b1 03
     mov bx, dx                                ; 89 d3
     sal bx, CL                                ; d3 e3
-    mov bl, byte [bx+04630h]                  ; 8a 9f 30 46
+    mov bl, byte [bx+04631h]                  ; 8a 9f 31 46
     cmp bl, cl                                ; 38 cb
     jc short 0214dh                           ; 72 0e
     jbe short 02154h                          ; 76 13
@@ -4309,9 +4309,9 @@ biosfn_write_pixel_:                         ; 0xc21ce LB 0x17f
     mov CL, strict byte 003h                  ; b1 03
     mov bx, ax                                ; 89 c3
     sal bx, CL                                ; d3 e3
-    cmp byte [bx+0462fh], 000h                ; 80 bf 2f 46 00
+    cmp byte [bx+04630h], 000h                ; 80 bf 30 46 00
     je short 02219h                           ; 74 18
-    mov al, byte [bx+04630h]                  ; 8a 87 30 46
+    mov al, byte [bx+04631h]                  ; 8a 87 31 46
     cmp al, cl                                ; 38 c8
     jc short 02215h                           ; 72 0c
     jbe short 0221fh                          ; 76 14
@@ -4372,7 +4372,7 @@ biosfn_write_pixel_:                         ; 0xc21ce LB 0x17f
     shr ax, 1                                 ; d1 e8
     mov si, strict word 00050h                ; be 50 00
     mul si                                    ; f7 e6
-    cmp byte [bx+04631h], 002h                ; 80 bf 31 46 02
+    cmp byte [bx+04632h], 002h                ; 80 bf 32 46 02
     jne short 022a4h                          ; 75 09
     mov bx, word [bp-008h]                    ; 8b 5e f8
     shr bx, 1                                 ; d1 eb
@@ -4394,7 +4394,7 @@ biosfn_write_pixel_:                         ; 0xc21ce LB 0x17f
     mov CL, strict byte 003h                  ; b1 03
     mov si, ax                                ; 89 c6
     sal si, CL                                ; d3 e6
-    cmp byte [si+04631h], 002h                ; 80 bc 31 46 02
+    cmp byte [si+04632h], 002h                ; 80 bc 32 46 02
     jne short 022eeh                          ; 75 1a
     mov al, byte [bp-008h]                    ; 8a 46 f8
     and al, cl                                ; 20 c8
@@ -4519,7 +4519,7 @@ biosfn_write_teletype_:                      ; 0xc234d LB 0x25f
     mov CL, strict byte 003h                  ; b1 03
     mov si, bx                                ; 89 de
     sal si, CL                                ; d3 e6
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 0244ch                          ; 75 46
     mov ax, word [bp-01ah]                    ; 8b 46 e6
     mul word [bp-018h]                        ; f7 66 e8
@@ -4537,7 +4537,7 @@ biosfn_write_teletype_:                      ; 0xc234d LB 0x25f
     sal ax, 1                                 ; d1 e0
     add cx, ax                                ; 01 c1
     mov bl, byte [bp-016h]                    ; 8a 5e ea
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     mov dx, cx                                ; 89 ca
     call 031a9h                               ; e8 74 0d
     cmp byte [bp-00ch], 003h                  ; 80 7e f4 03
@@ -4546,15 +4546,15 @@ biosfn_write_teletype_:                      ; 0xc234d LB 0x25f
     xor bh, bh                                ; 30 ff
     mov dx, cx                                ; 89 ca
     inc dx                                    ; 42
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     call 031a9h                               ; e8 5f 0d
     jmp short 02492h                          ; eb 46
-    mov bl, byte [bx+046aeh]                  ; 8a 9f ae 46
+    mov bl, byte [bx+046afh]                  ; 8a 9f af 46
     mov CL, strict byte 006h                  ; b1 06
     sal bx, CL                                ; d3 e3
-    mov bl, byte [bx+046c4h]                  ; 8a 9f c4 46
-    mov ah, byte [si+04631h]                  ; 8a a4 31 46
-    mov al, byte [si+04630h]                  ; 8a 84 30 46
+    mov bl, byte [bx+046c5h]                  ; 8a 9f c5 46
+    mov ah, byte [si+04632h]                  ; 8a a4 32 46
+    mov al, byte [si+04631h]                  ; 8a 84 31 46
     cmp AL, strict byte 003h                  ; 3c 03
     jc short 02470h                           ; 72 0c
     jbe short 02476h                          ; 76 10
@@ -4633,7 +4633,7 @@ biosfn_write_teletype_:                      ; 0xc234d LB 0x25f
     db  0feh, 0c8h
     ; dec al                                    ; fe c8
     mov byte [bp-012h], al                    ; 88 46 ee
-    cmp byte [si+0462fh], 000h                ; 80 bc 2f 46 00
+    cmp byte [si+04630h], 000h                ; 80 bc 30 46 00
     jne short 02569h                          ; 75 51
     mov ax, word [bp-01ah]                    ; 8b 46 e6
     mul word [bp-018h]                        ; f7 66 e8
@@ -4655,7 +4655,7 @@ biosfn_write_teletype_:                      ; 0xc234d LB 0x25f
     mov dx, cx                                ; 89 ca
     add dx, ax                                ; 01 c2
     inc dx                                    ; 42
-    mov ax, word [si+04632h]                  ; 8b 84 32 46
+    mov ax, word [si+04633h]                  ; 8b 84 33 46
     call 0319bh                               ; e8 51 0c
     mov dx, strict word 00001h                ; ba 01 00
     push dx                                   ; 52
@@ -4957,7 +4957,7 @@ biosfn_load_text_8_14_pat_:                  ; 0xc2764 LB 0x76
     mov di, bx                                ; 89 df
     sal di, CL                                ; d3 e7
     add di, word [bp-00ch]                    ; 03 7e f4
-    mov si, 05bech                            ; be ec 5b
+    mov si, 05bedh                            ; be ed 5b
     add si, ax                                ; 01 c6
     mov cx, strict word 0000eh                ; b9 0e 00
     mov dx, 0c000h                            ; ba 00 c0
@@ -5017,7 +5017,7 @@ biosfn_load_text_8_8_pat_:                   ; 0xc27da LB 0x74
     mov di, bx                                ; 89 df
     sal di, CL                                ; d3 e7
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 053ech                            ; 81 c6 ec 53
+    add si, 053edh                            ; 81 c6 ed 53
     mov cx, strict word 00008h                ; b9 08 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -5076,7 +5076,7 @@ biosfn_load_text_8_16_pat_:                  ; 0xc284e LB 0x74
     mov di, bx                                ; 89 df
     sal di, CL                                ; d3 e7
     add di, word [bp-00ch]                    ; 03 7e f4
-    add si, 069ech                            ; 81 c6 ec 69
+    add si, 069edh                            ; 81 c6 ed 69
     mov cx, strict word 00010h                ; b9 10 00
     mov dx, 0c000h                            ; ba 00 c0
     mov ax, 0a000h                            ; b8 00 a0
@@ -5212,7 +5212,7 @@ biosfn_read_state_info_:                     ; 0xc2982 LB 0x102
     push dx                                   ; 52
     push bx                                   ; 53
     mov cx, ds                                ; 8c d9
-    mov bx, 05382h                            ; bb 82 53
+    mov bx, 05383h                            ; bb 83 53
     mov dx, word [bp-00ah]                    ; 8b 56 f6
     mov ax, word [bp-008h]                    ; 8b 46 f8
     call 031e5h                               ; e8 4d 08
@@ -6151,7 +6151,7 @@ find_vga_entry_:                             ; 0xc3170 LB 0x2b
     xor bh, bh                                ; 30 ff
     mov CL, strict byte 003h                  ; b1 03
     sal bx, CL                                ; d3 e3
-    cmp dl, byte [bx+0462eh]                  ; 3a 97 2e 46
+    cmp dl, byte [bx+0462fh]                  ; 3a 97 2f 46
     jne short 0317eh                          ; 75 ec
     mov ah, al                                ; 88 c4
     mov al, ah                                ; 88 e0
@@ -7432,10 +7432,10 @@ vesa_pm_end:                                 ; 0xc4514 LB 0x1
   ; Padding 0xeb bytes at 0xc4515
   times 235 db 0
 
-section _DATA progbits vstart=0x4600 align=1 ; size=0x371e class=DATA group=DGROUP
-_msg_vga_init:                               ; 0xc4600 LB 0x2e
-    db  'Oracle VM VirtualBox Version 5.1.8 VGA BIOS', 00dh, 00ah, 000h
-_vga_modes:                                  ; 0xc462e LB 0x80
+section _DATA progbits vstart=0x4600 align=1 ; size=0x371f class=DATA group=DGROUP
+_msg_vga_init:                               ; 0xc4600 LB 0x2f
+    db  'Oracle VM VirtualBox Version 5.1.10 VGA BIOS', 00dh, 00ah, 000h
+_vga_modes:                                  ; 0xc462f LB 0x80
     db  000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
     db  002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
     db  004h, 001h, 002h, 002h, 000h, 0b8h, 0ffh, 001h, 005h, 001h, 002h, 002h, 000h, 0b8h, 0ffh, 001h
@@ -7444,11 +7444,11 @@ _vga_modes:                                  ; 0xc462e LB 0x80
     db  00fh, 001h, 003h, 001h, 000h, 0a0h, 0ffh, 000h, 010h, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
     db  011h, 001h, 003h, 001h, 000h, 0a0h, 0ffh, 002h, 012h, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
     db  013h, 001h, 005h, 008h, 000h, 0a0h, 0ffh, 003h, 06ah, 001h, 004h, 004h, 000h, 0a0h, 0ffh, 002h
-_line_to_vpti:                               ; 0xc46ae LB 0x10
+_line_to_vpti:                               ; 0xc46af LB 0x10
     db  017h, 017h, 018h, 018h, 004h, 005h, 006h, 007h, 00dh, 00eh, 011h, 012h, 01ah, 01bh, 01ch, 01dh
-_dac_regs:                                   ; 0xc46be LB 0x4
+_dac_regs:                                   ; 0xc46bf LB 0x4
     dd  0ff3f3f3fh
-_video_param_table:                          ; 0xc46c2 LB 0x780
+_video_param_table:                          ; 0xc46c3 LB 0x780
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
@@ -7569,7 +7569,7 @@ _video_param_table:                          ; 0xc46c2 LB 0x780
     db  072h, 0f0h, 000h, 060h, 000h, 000h, 000h, 000h, 000h, 000h, 059h, 08dh, 057h, 032h, 000h, 057h
     db  073h, 0e3h, 0ffh, 000h, 001h, 002h, 003h, 004h, 005h, 014h, 007h, 038h, 039h, 03ah, 03bh, 03ch
     db  03dh, 03eh, 03fh, 001h, 000h, 00fh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 005h, 00fh, 0ffh
-_palette0:                                   ; 0xc4e42 LB 0xc0
+_palette0:                                   ; 0xc4e43 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
@@ -7582,7 +7582,7 @@ _palette0:                                   ; 0xc4e42 LB 0xc0
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah
     db  02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 02ah, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
     db  03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh, 03fh
-_palette1:                                   ; 0xc4f02 LB 0xc0
+_palette1:                                   ; 0xc4f03 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah
     db  000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah, 000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah
@@ -7595,7 +7595,7 @@ _palette1:                                   ; 0xc4f02 LB 0xc0
     db  015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh, 015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh
     db  015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
-_palette2:                                   ; 0xc4fc2 LB 0xc0
+_palette2:                                   ; 0xc4fc3 LB 0xc0
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 02ah, 000h, 02ah, 02ah, 02ah, 000h, 000h, 015h, 000h, 000h, 03fh, 000h, 02ah
     db  015h, 000h, 02ah, 03fh, 02ah, 000h, 015h, 02ah, 000h, 03fh, 02ah, 02ah, 015h, 02ah, 02ah, 03fh
@@ -7608,7 +7608,7 @@ _palette2:                                   ; 0xc4fc2 LB 0xc0
     db  015h, 015h, 000h, 015h, 015h, 02ah, 015h, 03fh, 000h, 015h, 03fh, 02ah, 03fh, 015h, 000h, 03fh
     db  015h, 02ah, 03fh, 03fh, 000h, 03fh, 03fh, 02ah, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
-_palette3:                                   ; 0xc5082 LB 0x300
+_palette3:                                   ; 0xc5083 LB 0x300
     db  000h, 000h, 000h, 000h, 000h, 02ah, 000h, 02ah, 000h, 000h, 02ah, 02ah, 02ah, 000h, 000h, 02ah
     db  000h, 02ah, 02ah, 015h, 000h, 02ah, 02ah, 02ah, 015h, 015h, 015h, 015h, 015h, 03fh, 015h, 03fh
     db  015h, 015h, 03fh, 03fh, 03fh, 015h, 015h, 03fh, 015h, 03fh, 03fh, 03fh, 015h, 03fh, 03fh, 03fh
@@ -7657,19 +7657,19 @@ _palette3:                                   ; 0xc5082 LB 0x300
     db  00bh, 010h, 00bh, 00bh, 010h, 00ch, 00bh, 010h, 00dh, 00bh, 010h, 00fh, 00bh, 010h, 010h, 00bh
     db  00fh, 010h, 00bh, 00dh, 010h, 00bh, 00ch, 010h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_static_functionality:                       ; 0xc5382 LB 0x10
+_static_functionality:                       ; 0xc5383 LB 0x10
     db  0ffh, 0e0h, 00fh, 000h, 000h, 000h, 000h, 007h, 002h, 008h, 0e7h, 00ch, 000h, 000h, 000h, 000h
-_dcc_table:                                  ; 0xc5392 LB 0x24
+_dcc_table:                                  ; 0xc5393 LB 0x24
     db  010h, 001h, 007h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h
-_secondary_save_area:                        ; 0xc53b6 LB 0x1a
-    db  01ah, 000h, 092h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+_secondary_save_area:                        ; 0xc53b7 LB 0x1a
+    db  01ah, 000h, 093h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_video_save_pointer_table:                   ; 0xc53d0 LB 0x1c
-    db  0c2h, 046h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  0b6h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont8:                                   ; 0xc53ec LB 0x800
+_video_save_pointer_table:                   ; 0xc53d1 LB 0x1c
+    db  0c3h, 046h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+    db  0b7h, 053h, 000h, 0c0h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+_vgafont8:                                   ; 0xc53ed LB 0x800
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07eh, 081h, 0a5h, 081h, 0bdh, 099h, 081h, 07eh
     db  07eh, 0ffh, 0dbh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh, 06ch, 0feh, 0feh, 0feh, 07ch, 038h, 010h, 000h
     db  010h, 038h, 07ch, 0feh, 07ch, 038h, 010h, 000h, 038h, 07ch, 038h, 0feh, 0feh, 07ch, 038h, 07ch
@@ -7798,7 +7798,7 @@ _vgafont8:                                   ; 0xc53ec LB 0x800
     db  000h, 000h, 000h, 000h, 018h, 000h, 000h, 000h, 00fh, 00ch, 00ch, 00ch, 0ech, 06ch, 03ch, 01ch
     db  078h, 06ch, 06ch, 06ch, 06ch, 000h, 000h, 000h, 070h, 018h, 030h, 060h, 078h, 000h, 000h, 000h
     db  000h, 000h, 03ch, 03ch, 03ch, 03ch, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont14:                                  ; 0xc5bec LB 0xe00
+_vgafont14:                                  ; 0xc5bed LB 0xe00
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  07eh, 081h, 0a5h, 081h, 081h, 0bdh, 099h, 081h, 07eh, 000h, 000h, 000h, 000h, 000h, 07eh, 0ffh
     db  0dbh, 0ffh, 0ffh, 0c3h, 0e7h, 0ffh, 07eh, 000h, 000h, 000h, 000h, 000h, 000h, 06ch, 0feh, 0feh
@@ -8023,7 +8023,7 @@ _vgafont14:                                  ; 0xc5bec LB 0xe00
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 070h, 0d8h, 030h, 060h, 0c8h, 0f8h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont16:                                  ; 0xc69ec LB 0x1000
+_vgafont16:                                  ; 0xc69ed LB 0x1000
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 07eh, 081h, 0a5h, 081h, 081h, 0bdh, 099h, 081h, 081h, 07eh, 000h, 000h, 000h, 000h
     db  000h, 000h, 07eh, 0ffh, 0dbh, 0ffh, 0ffh, 0c3h, 0e7h, 0ffh, 0ffh, 07eh, 000h, 000h, 000h, 000h
@@ -8280,7 +8280,7 @@ _vgafont16:                                  ; 0xc69ec LB 0x1000
     db  000h, 070h, 0d8h, 030h, 060h, 0c8h, 0f8h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 07ch, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-_vgafont14alt:                               ; 0xc79ec LB 0x12d
+_vgafont14alt:                               ; 0xc79ed LB 0x12d
     db  01dh, 000h, 000h, 000h, 000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h, 000h, 000h, 000h, 022h
     db  000h, 063h, 063h, 063h, 022h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 02bh, 000h
     db  000h, 000h, 018h, 018h, 018h, 0ffh, 018h, 018h, 018h, 000h, 000h, 000h, 000h, 02dh, 000h, 000h
@@ -8300,7 +8300,7 @@ _vgafont14alt:                               ; 0xc79ec LB 0x12d
     db  000h, 0fch, 066h, 066h, 07ch, 062h, 066h, 06fh, 066h, 066h, 0f3h, 000h, 000h, 000h, 0f1h, 000h
     db  000h, 018h, 018h, 018h, 0ffh, 018h, 018h, 018h, 000h, 0ffh, 000h, 000h, 000h, 0f6h, 000h, 000h
     db  018h, 018h, 000h, 000h, 0ffh, 000h, 000h, 018h, 018h, 000h, 000h, 000h, 000h
-_vgafont16alt:                               ; 0xc7b19 LB 0x145
+_vgafont16alt:                               ; 0xc7b1a LB 0x144
     db  01dh, 000h, 000h, 000h, 000h, 000h, 024h, 066h, 0ffh, 066h, 024h, 000h, 000h, 000h, 000h, 000h
     db  000h, 030h, 000h, 000h, 03ch, 066h, 0c3h, 0c3h, 0dbh, 0dbh, 0c3h, 0c3h, 066h, 03ch, 000h, 000h
     db  000h, 000h, 04dh, 000h, 000h, 0c3h, 0e7h, 0ffh, 0ffh, 0dbh, 0c3h, 0c3h, 0c3h, 0c3h, 0c3h, 000h
@@ -8321,33 +8321,35 @@ _vgafont16alt:                               ; 0xc7b19 LB 0x145
     db  09eh, 000h, 0fch, 066h, 066h, 07ch, 062h, 066h, 06fh, 066h, 066h, 066h, 0f3h, 000h, 000h, 000h
     db  000h, 0abh, 000h, 0c0h, 0c0h, 0c2h, 0c6h, 0cch, 018h, 030h, 060h, 0ceh, 09bh, 006h, 00ch, 01fh
     db  000h, 000h, 0ach, 000h, 0c0h, 0c0h, 0c2h, 0c6h, 0cch, 018h, 030h, 066h, 0ceh, 096h, 03eh, 006h
-    db  006h, 000h, 000h, 000h, 000h
+    db  006h, 000h, 000h, 000h
 _vbebios_copyright:                          ; 0xc7c5e LB 0x15
     db  'VirtualBox VESA BIOS', 000h
 _vbebios_vendor_name:                        ; 0xc7c73 LB 0x13
     db  'Oracle Corporation', 000h
 _vbebios_product_name:                       ; 0xc7c86 LB 0x21
     db  'Oracle VM VirtualBox VBE Adapter', 000h
-_vbebios_product_revision:                   ; 0xc7ca7 LB 0x23
-    db  'Oracle VM VirtualBox Version 5.1.8', 000h
-_vbebios_info_string:                        ; 0xc7cca LB 0x2b
+_vbebios_product_revision:                   ; 0xc7ca7 LB 0x24
+    db  'Oracle VM VirtualBox Version 5.1.10', 000h
+_vbebios_info_string:                        ; 0xc7ccb LB 0x2b
     db  'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
-_no_vbebios_info_string:                     ; 0xc7cf5 LB 0x29
+_no_vbebios_info_string:                     ; 0xc7cf6 LB 0x29
     db  'No VirtualBox VBE support available!', 00dh, 00ah, 00dh, 00ah, 000h
 
-section CONST progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
+  ; Padding 0x1 bytes at 0xc7d1f
+    db  001h
 
-section CONST2 progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
+section CONST progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
 
-  ; Padding 0x2e2 bytes at 0xc7d1e
-    db  001h, 000h, 000h, 000h, 000h, 001h, 000h, 000h, 000h, 000h, 000h, 000h, 02fh, 068h, 06fh, 06dh
-    db  065h, 02fh, 066h, 06dh, 033h, 02fh, 073h, 072h, 063h, 02fh, 076h, 062h, 06fh, 078h, 02dh, 035h
-    db  02eh, 031h, 02fh, 06fh, 075h, 074h, 02fh, 06ch, 069h, 06eh, 075h, 078h, 02eh, 061h, 06dh, 064h
-    db  036h, 034h, 02fh, 072h, 065h, 06ch, 065h, 061h, 073h, 065h, 02fh, 06fh, 062h, 06ah, 02fh, 056h
-    db  042h, 06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 038h, 030h, 038h, 036h, 02fh, 056h
-    db  042h, 06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 038h, 030h, 038h, 036h, 02eh, 073h
-    db  079h, 06dh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
+section CONST2 progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
+
+  ; Padding 0x2e0 bytes at 0xc7d20
+    db  000h, 000h, 000h, 000h, 001h, 000h, 000h, 000h, 000h, 000h, 000h, 02fh, 068h, 06fh, 06dh, 065h
+    db  02fh, 066h, 06dh, 033h, 02fh, 073h, 072h, 063h, 02fh, 076h, 062h, 06fh, 078h, 02dh, 035h, 02eh
+    db  031h, 02fh, 06fh, 075h, 074h, 02fh, 06ch, 069h, 06eh, 075h, 078h, 02eh, 061h, 06dh, 064h, 036h
+    db  034h, 02fh, 072h, 065h, 06ch, 065h, 061h, 073h, 065h, 02fh, 06fh, 062h, 06ah, 02fh, 056h, 042h
+    db  06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 038h, 030h, 038h, 036h, 02fh, 056h, 042h
+    db  06fh, 078h, 056h, 067h, 061h, 042h, 069h, 06fh, 073h, 038h, 030h, 038h, 036h, 02eh, 073h, 079h
+    db  06dh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
@@ -8386,4 +8388,4 @@ section CONST2 progbits vstart=0x7d1e align=1 ; size=0x0 class=DATA group=DGROUP
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
     db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
-    db  000h, 0ffh
+    db  000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 04fh
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
index 4414a2f..2ef95ef 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
@@ -1 +1 @@
-65fac054c07ec9ad1f8222b00ed8d950 *VBoxVgaBios8086.rom
+70f2d058fc399d22affae7a57381d6b4 *VBoxVgaBios8086.rom
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp
index 7276a26..aa967b0 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp
@@ -3759,24 +3759,12 @@ static void vmsvgaSetTraces(PVGASTATE pThis, bool fTraces)
 }
 
 /**
- * Callback function for mapping a PCI I/O region.
- *
- * @return VBox status code.
- * @param   pPciDev         Pointer to PCI device.
- *                          Use pPciDev->pDevIns to get the device instance.
- * @param   iRegion         The region number.
- * @param   GCPhysAddress   Physical address of the region.
- *                          If iType is PCI_ADDRESS_SPACE_IO, this is an
- *                          I/O port, else it's a physical address.
- *                          This address is *NOT* relative
- *                          to pci_mem_base like earlier!
- * @param   enmType         One of the PCI_ADDRESS_SPACE_* values.
+ * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-DECLCALLBACK(int) vmsvgaR3IORegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb,
-                                      PCIADDRESSSPACE enmType)
+DECLCALLBACK(int) vmsvgaR3IORegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                      RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     int         rc;
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
     PVGASTATE   pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
 
     Log(("vgasvgaR3IORegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
@@ -3813,7 +3801,7 @@ DECLCALLBACK(int) vmsvgaR3IORegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS
             /*
              * Mapping the FIFO RAM.
              */
-            rc = PDMDevHlpMMIO2Map(pDevIns, iRegion, GCPhysAddress);
+            rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
             AssertRC(rc);
 
 # ifdef DEBUG_FIFO_ACCESS
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA.h b/src/VBox/Devices/Graphics/DevVGA-SVGA.h
index 2b26550..18351a7 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA.h
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA.h
@@ -1,3 +1,4 @@
+/* $Id: DevVGA-SVGA.h $ */
 /** @file
  * VMware SVGA device
  */
@@ -12,8 +13,9 @@
  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
-#ifndef __DEVVGA_SVGA_H__
-#define __DEVVGA_SVGA_H__
+
+#ifndef ___DevVGA_SVGA_h___
+#define ___DevVGA_SVGA_h___
 
 
 /** Default FIFO size. */
@@ -40,9 +42,11 @@
 #define VMSVGA_ACTION_CHANGEMODE_BIT    0
 #define VMSVGA_ACTION_CHANGEMODE        RT_BIT(VMSVGA_ACTION_CHANGEMODE_BIT)
 
-DECLCALLBACK(int) vmsvgaR3IORegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType);
+DECLCALLBACK(int) vmsvgaR3IORegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                      RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType);
 
-DECLCALLBACK(void) vmsvgaPortSetViewport(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
+DECLCALLBACK(void) vmsvgaPortSetViewport(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId,
+                                         uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
 
 int vmsvgaInit(PPDMDEVINS pDevIns);
 int vmsvgaReset(PPDMDEVINS pDevIns);
@@ -53,4 +57,5 @@ int vmsvgaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
 DECLCALLBACK(void) vmsvgaR3PowerOn(PPDMDEVINS pDevIns);
 DECLCALLBACK(void) vmsvgaR3PowerOff(PPDMDEVINS pDevIns);
 
-#endif  /* __DEVVGA_SVGA_H__ */
+#endif
+
diff --git a/src/VBox/Devices/Graphics/DevVGA.cpp b/src/VBox/Devices/Graphics/DevVGA.cpp
index 7108e0f..65f26e0 100644
--- a/src/VBox/Devices/Graphics/DevVGA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA.cpp
@@ -5397,27 +5397,18 @@ int vgaR3UnregisterVRAMHandler(PVGASTATE pVGAState)
 /* -=-=-=-=-=- Ring 3: PCI Device -=-=-=-=-=- */
 
 /**
- * Callback function for unmapping and/or mapping the VRAM MMIO2 region (called by the PCI bus).
- *
- * @return VBox status code.
- * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param   iRegion         The region number.
- * @param   GCPhysAddress   Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
- *                          I/O port, else it's a physical address.
- *                          This address is *NOT* relative to pci_mem_base like earlier!
- * @param   enmType         One of the PCI_ADDRESS_SPACE_* values.
+ * @callback_method_impl{FNPCIIOREGIONMAP, Mapping/unmapping the VRAM MMI2 region}
  */
-static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
-                                          RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) vgaR3IORegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                          RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF1(cb);
     int         rc;
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
     PVGASTATE   pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
     Log(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
 #ifdef VBOX_WITH_VMSVGA
-    AssertReturn(   (iRegion == ((pThis->fVMSVGAEnabled) ? 1 : 0))
-                 && (enmType == ((pThis->fVMSVGAEnabled) ? PCI_ADDRESS_SPACE_MEM : PCI_ADDRESS_SPACE_MEM_PREFETCH)),
+    AssertReturn(   iRegion == (pThis->fVMSVGAEnabled ? 1U : 0U)
+                 && enmType == (pThis->fVMSVGAEnabled ? PCI_ADDRESS_SPACE_MEM : PCI_ADDRESS_SPACE_MEM_PREFETCH),
                  VERR_INTERNAL_ERROR);
 #else
     AssertReturn(iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
@@ -5431,7 +5422,7 @@ static DECLCALLBACK(int) vgaR3IORegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int i
         /*
          * Mapping the VRAM.
          */
-        rc = PDMDevHlpMMIO2Map(pDevIns, iRegion, GCPhysAddress);
+        rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
         AssertRC(rc);
         if (RT_SUCCESS(rc))
         {
@@ -6206,6 +6197,47 @@ static DECLCALLBACK(int)   vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
     AssertRCReturn(rc, rc);
 
     /*
+     * PCI device registration.
+     */
+    rc = PDMDevHlpPCIRegister(pDevIns, &pThis->Dev);
+    if (RT_FAILURE(rc))
+        return rc;
+    /*AssertMsg(pThis->Dev.uDevFn == 16 || iInstance != 0, ("pThis->Dev.uDevFn=%d\n", pThis->Dev.uDevFn));*/
+    if (pThis->Dev.uDevFn != 16 && iInstance == 0)
+        Log(("!!WARNING!!: pThis->dev.uDevFn=%d (ignore if testcase or not started by Main)\n", pThis->Dev.uDevFn));
+
+#ifdef VBOX_WITH_VMSVGA
+    if (pThis->fVMSVGAEnabled)
+    {
+        /* Register the io command ports. */
+        rc = PDMDevHlpPCIIORegionRegister (pDevIns, 0 /* iRegion */, 0x10, PCI_ADDRESS_SPACE_IO, vmsvgaR3IORegionMap);
+        if (RT_FAILURE (rc))
+            return rc;
+        /* VMware's MetalKit doesn't like PCI_ADDRESS_SPACE_MEM_PREFETCH */
+        rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1 /* iRegion */, pThis->vram_size,
+                                          PCI_ADDRESS_SPACE_MEM /* PCI_ADDRESS_SPACE_MEM_PREFETCH */, vgaR3IORegionMap);
+        if (RT_FAILURE(rc))
+            return rc;
+        rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2 /* iRegion */, VMSVGA_FIFO_SIZE,
+                                          PCI_ADDRESS_SPACE_MEM /* PCI_ADDRESS_SPACE_MEM_PREFETCH */, vmsvgaR3IORegionMap);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+    else
+#endif /* VBOX_WITH_VMSVGA */
+    {
+#ifdef VBOX_WITH_VMSVGA
+        int iPCIRegionVRAM = (pThis->fVMSVGAEnabled) ? 1 : 0;
+#else
+        int iPCIRegionVRAM = 0;
+#endif
+        rc = PDMDevHlpPCIIORegionRegister(pDevIns, iPCIRegionVRAM, pThis->vram_size,
+                                          PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    /*
      * Allocate the VRAM and map the first 512KB of it into GC so we can speed up VGA support.
      */
 #ifdef VBOX_WITH_VMSVGA
@@ -6216,7 +6248,8 @@ static DECLCALLBACK(int)   vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
         /*
          * Allocate and initialize the FIFO MMIO2 memory.
          */
-        rc = PDMDevHlpMMIO2Register(pDevIns, 2 /*iRegion*/, VMSVGA_FIFO_SIZE, 0 /*fFlags*/, (void **)&pThis->svga.pFIFOR3, "VMSVGA-FIFO");
+        rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->Dev, 2 /*iRegion*/, VMSVGA_FIFO_SIZE,
+                                    0 /*fFlags*/, (void **)&pThis->svga.pFIFOR3, "VMSVGA-FIFO");
         if (RT_FAILURE(rc))
             return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                         N_("Failed to allocate %u bytes of memory for the VMSVGA device"), VMSVGA_FIFO_SIZE);
@@ -6226,19 +6259,20 @@ static DECLCALLBACK(int)   vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
 #else
     int iPCIRegionVRAM = 0;
 #endif
-    rc = PDMDevHlpMMIO2Register(pDevIns, iPCIRegionVRAM, pThis->vram_size, 0, (void **)&pThis->vram_ptrR3, "VRam");
+    rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->Dev, iPCIRegionVRAM, pThis->vram_size, 0, (void **)&pThis->vram_ptrR3, "VRam");
     AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMIO2Register(%#x,) -> %Rrc\n", pThis->vram_size, rc), rc);
     pThis->vram_ptrR0 = (RTR0PTR)pThis->vram_ptrR3; /** @todo @bugref{1865} Map parts into R0 or just use PGM access (Mac only). */
 
     if (pThis->fGCEnabled)
     {
         RTRCPTR pRCMapping = 0;
-        rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, iPCIRegionVRAM, 0 /* off */,  VGA_MAPPING_SIZE, "VGA VRam", &pRCMapping);
+        rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, &pThis->Dev, iPCIRegionVRAM, 0 /* off */,  VGA_MAPPING_SIZE,
+                                      "VGA VRam", &pRCMapping);
         AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", VGA_MAPPING_SIZE, rc), rc);
         pThis->vram_ptrRC = pRCMapping;
-# ifdef VBOX_WITH_VMSVGA
+#ifdef VBOX_WITH_VMSVGA
         /* Don't need a mapping in RC */
-# endif
+#endif
     }
 
 #if defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
@@ -6532,42 +6566,6 @@ static DECLCALLBACK(int)   vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
         return rc;
 
     /*
-     * PCI device registration.
-     */
-    rc = PDMDevHlpPCIRegister(pDevIns, &pThis->Dev);
-    if (RT_FAILURE(rc))
-        return rc;
-    /*AssertMsg(pThis->Dev.devfn == 16 || iInstance != 0, ("pThis->Dev.devfn=%d\n", pThis->Dev.devfn));*/
-    if (pThis->Dev.devfn != 16 && iInstance == 0)
-        Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or not started by Main)\n", pThis->Dev.devfn));
-
-#ifdef VBOX_WITH_VMSVGA
-    if (pThis->fVMSVGAEnabled)
-    {
-        /* Register the io command ports. */
-        rc = PDMDevHlpPCIIORegionRegister (pDevIns, 0 /* iRegion */, 0x10, PCI_ADDRESS_SPACE_IO, vmsvgaR3IORegionMap);
-        if (RT_FAILURE (rc))
-            return rc;
-        /* VMware's MetalKit doesn't like PCI_ADDRESS_SPACE_MEM_PREFETCH */
-        rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1 /* iRegion */, pThis->vram_size,
-                                          PCI_ADDRESS_SPACE_MEM /* PCI_ADDRESS_SPACE_MEM_PREFETCH */, vgaR3IORegionMap);
-        if (RT_FAILURE(rc))
-            return rc;
-        rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2 /* iRegion */, VMSVGA_FIFO_SIZE,
-                                          PCI_ADDRESS_SPACE_MEM /* PCI_ADDRESS_SPACE_MEM_PREFETCH */, vmsvgaR3IORegionMap);
-        if (RT_FAILURE(rc))
-            return rc;
-    }
-    else
-#endif /* VBOX_WITH_VMSVGA */
-    {
-        rc = PDMDevHlpPCIIORegionRegister(pDevIns, iPCIRegionVRAM, pThis->vram_size,
-                                          PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
-        if (RT_FAILURE(rc))
-            return rc;
-    }
-
-    /*
      * Create the refresh timer.
      */
     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_REAL, vgaTimerRefresh,
diff --git a/src/VBox/Devices/Graphics/DevVGA.h b/src/VBox/Devices/Graphics/DevVGA.h
index 5f43251..9a8125b 100644
--- a/src/VBox/Devices/Graphics/DevVGA.h
+++ b/src/VBox/Devices/Graphics/DevVGA.h
@@ -501,7 +501,7 @@ typedef struct VGAState {
     /** The critical section protect the instance data. */
     PDMCRITSECT                 CritSect;
     /** The PCI device. */
-    PCIDEVICE                   Dev;
+    PDMPCIDEV                   Dev;
 
     STAMPROFILE                 StatRZMemoryRead;
     STAMPROFILE                 StatR3MemoryRead;
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index 7b54167..c89b433 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -25,7 +25,7 @@ endif
 
 # Include sub-makefiles.
 include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
-include $(PATH_SUB_CURRENT)/Audio/testcase/Makefile.kmk
+include $(PATH_SUB_CURRENT)/$(VBOX_AUDIO_PATH_SOURCES)/testcase/Makefile.kmk
 include $(PATH_SUB_CURRENT)/Input/testcase/Makefile.kmk
 ifdef VBOX_WITH_TESTCASES
  include $(PATH_SUB_CURRENT)/Samples/Makefile.kmk
@@ -540,51 +540,53 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  # Enable Audio Queues implementation for macOS hosts (Core Audio backend).
  VBoxDD_DEFS.darwin += VBOX_WITH_AUDIO_CA_QUEUES
 
- VBoxDD_SOURCES         += \
-	Audio/DevIchAc97.cpp \
-	Audio/DevSB16.cpp \
-	Audio/DevIchHda.cpp \
-	Audio/DevIchHdaCodec.cpp \
-	Audio/AudioMixBuffer.cpp \
-	Audio/AudioMixer.cpp \
-	Audio/DrvAudio.cpp \
-	Audio/DrvAudioCommon.cpp \
-	Audio/DrvHostNullAudio.cpp
+ VBoxDD_DEFS  += $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
+
+ VBoxDD_SOURCES += \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DevIchAc97.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DevSB16.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DevHDA.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/HDACodec.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/AudioMixBuffer.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/AudioMixer.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DrvAudio.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DrvAudioCommon.cpp \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostNullAudio.cpp
 
  ifdef VBOX_WITH_AUDIO_DEBUG
   VBoxDD_DEFS    += VBOX_WITH_AUDIO_DEBUG
   VBoxDD_SOURCES += \
-	Audio/DrvHostDebugAudio.cpp
+	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostDebugAudio.cpp
  endif
 
  ifeq ($(KBUILD_TARGET),darwin)
   VBoxDD_SOURCES += \
-	Audio/DrvHostCoreAudio.cpp
+	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostCoreAudio.cpp
  endif
 
  ifeq ($(KBUILD_TARGET),win)
   VBoxDD_SOURCES += \
-	Audio/DrvHostDSound.cpp
+	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostDSound.cpp
  endif
 
  ifdef VBOX_WITH_AUDIO_OSS
   VBoxDD_DEFS    += VBOX_WITH_AUDIO_OSS
   VBoxDD_SOURCES += \
-	Audio/DrvHostOSSAudio.cpp
+	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostOSSAudio.cpp
  endif
 
  ifdef VBOX_WITH_AUDIO_ALSA
   VBoxDD_DEFS    += VBOX_WITH_AUDIO_ALSA
   VBoxDD_SOURCES += \
-	Audio/DrvHostALSAAudio.cpp \
-	Audio/alsa_stubs.c
+	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostALSAAudio.cpp \
+	$(VBOX_AUDIO_PATH_SOURCES)/alsa_stubs.c
  endif
 
  ifdef VBOX_WITH_AUDIO_PULSE
   VBoxDD_DEFS    += VBOX_WITH_AUDIO_PULSE
   VBoxDD_SOURCES += \
-	Audio/DrvHostPulseAudio.cpp \
-	Audio/pulse_stubs.c
+	$(VBOX_AUDIO_PATH_SOURCES)/DrvHostPulseAudio.cpp \
+	$(VBOX_AUDIO_PATH_SOURCES)/pulse_stubs.c
  endif
 
  # --- WARNING! SLIRP MESS AHEAD! ;-) ---
@@ -881,8 +883,9 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
   	Parallel/DevParallel.cpp \
   	VMMDev/VMMDevTesting.cpp
 
+  VBoxDDRC_DEFS         += $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
   VBoxDDRC_SOURCES      += \
- 	Audio/DevIchHda.cpp
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DevHDA.cpp
 
   ifdef VBOX_WITH_E1000
    VBoxDDRC_DEFS        += VBOX_WITH_E1000
@@ -1046,10 +1049,13 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  	Parallel/DevParallel.cpp \
  	VMMDev/VMMDevTesting.cpp \
  	Network/DrvIntNet.cpp \
- 	Network/DrvDedicatedNic.cpp \
- 	Audio/DevIchHda.cpp
+ 	Network/DrvDedicatedNic.cpp
+
+ VBoxDDR0_DEFS          += $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
+ VBoxDDR0_SOURCES       += \
+ 	$(VBOX_AUDIO_PATH_SOURCES)/DevHDA.cpp
 
- VBoxDDR0_SOURCES.win += Parallel/DrvHostParallel.cpp
+ VBoxDDR0_SOURCES.win   += Parallel/DrvHostParallel.cpp
 
  VBoxDDR0_DEFS          += \
 	$(if $(VBOX_WITH_HGSMI),VBOX_WITH_HGSMI,) \
diff --git a/src/VBox/Devices/Network/DevE1000.cpp b/src/VBox/Devices/Network/DevE1000.cpp
index bd3e044..b5713b7 100644
--- a/src/VBox/Devices/Network/DevE1000.cpp
+++ b/src/VBox/Devices/Network/DevE1000.cpp
@@ -47,7 +47,11 @@
 #include "DevE1000Phy.h"
 
 
-/* Options *******************************************************************/
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** @name E1000 Build Options
+ * @{ */
 /** @def E1K_INIT_RA0
  * E1K_INIT_RA0 forces E1000 to set the first entry in Receive Address filter
  * table to MAC address obtained from CFGM. Most guests read MAC address from
@@ -61,6 +65,16 @@
  * that requires it is Mac OS X (see @bugref{4657}).
  */
 #define E1K_LSC_ON_SLU
+/** @def E1K_INIT_LINKUP_DELAY
+ * E1K_INIT_LINKUP_DELAY prevents the link going up while the driver is still
+ * in init (see @bugref{8624}).
+ */
+#define E1K_INIT_LINKUP_DELAY (500 * 1000)
+/** @def E1K_IMS_INT_DELAY_NS
+ * E1K_IMS_INT_DELAY_NS prevents interrupt storms in Windows guests on enabling
+ * interrupts (see @bugref{8624}).
+ */
+#define E1K_IMS_INT_DELAY_NS 100
 /** @def E1K_TX_DELAY
  * E1K_TX_DELAY aims to improve guest-host transfer rate for TCP streams by
  * preventing packets to be sent immediately. It allows to send several
@@ -116,6 +130,11 @@
  * order to work properly (see @bugref{6217}).
  */
 #define E1K_WITH_RXD_CACHE
+/** @def E1K_WITH_PREREG_MMIO
+ * E1K_WITH_PREREG_MMIO enables a new style MMIO registration and is
+ * currently only done for testing the relateted PDM, IOM and PGM code. */
+//#define E1K_WITH_PREREG_MMIO
+/* @} */
 /* End of Options ************************************************************/
 
 #ifdef E1K_WITH_TXD_CACHE
@@ -1069,7 +1088,7 @@ struct E1kState_st
     /** Base port of I/O space region. */
     RTIOPORT    IOPortBase;
     /** EMT: */
-    PCIDEVICE   pciDevice;
+    PDMPCIDEV   pciDevice;
     /** EMT: Last time the interrupt was acknowledged.  */
     uint64_t    u64AckedAt;
     /** All: Used for eliminating spurious interrupts. */
@@ -1240,10 +1259,10 @@ struct E1kState_st
     uint32_t    uStatInt;
     uint32_t    uStatIntTry;
     uint32_t    uStatIntLower;
-    uint32_t    uStatIntDly;
+    uint32_t    uStatNoIntICR;
     int32_t     iStatIntLost;
     int32_t     iStatIntLostOne;
-    uint32_t    uStatDisDly;
+    uint32_t    uStatIntIMS;
     uint32_t    uStatIntSkip;
     uint32_t    uStatIntLate;
     uint32_t    uStatIntMasked;
@@ -2518,6 +2537,7 @@ static int e1kHandleRxPacket(PE1KSTATE pThis, const void *pvBuf, size_t cb, E1KR
 }
 
 
+#ifdef IN_RING3
 /**
  * Bring the link up after the configured delay, 5 seconds by default.
  *
@@ -2531,7 +2551,6 @@ DECLINLINE(void) e1kBringLinkUpDelayed(PE1KSTATE pThis)
     e1kArmTimer(pThis, pThis->CTX_SUFF(pLUTimer), pThis->cMsLinkUpDelay * 1000);
 }
 
-#ifdef IN_RING3
 /**
  * Bring up the link immediately.
  *
@@ -2648,18 +2667,20 @@ static int e1kRegWriteCTRL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uin
     }
     else
     {
+        /*
+         * When the guest changes 'Set Link Up' bit from 0 to 1 we check if
+         * the link is down and the cable is connected, and if they are we
+         * bring the link up, see @bugref{8624}.
+         */
         if (   (value & CTRL_SLU)
+            && !(CTRL & CTRL_SLU)
             && pThis->fCableConnected
             && !(STATUS & STATUS_LU))
         {
-            /* The driver indicates that we should bring up the link */
-            /* Do so in 5 seconds (by default). */
-            e1kBringLinkUpDelayed(pThis);
             /*
-             * Change the status (but not PHY status) anyway as Windows expects
-             * it for 82543GC.
-             */
-            STATUS |= STATUS_LU;
+             * The driver indicates that we should bring up the link. Our default 5-second delay is too long,
+             * as Linux guests detect Tx hang after 2 seconds. Let's use 500 ms delay instead. */
+            e1kArmTimer(pThis, pThis->CTX_SUFF(pLUTimer), E1K_INIT_LINKUP_DELAY);
         }
         if (value & CTRL_VME)
         {
@@ -2902,6 +2923,8 @@ static int e1kRegReadICR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint3
     {
         if (value)
         {
+            if (!pThis->fIntRaised)
+                E1K_INC_ISTAT_CNT(pThis->uStatNoIntICR);
             /*
              * Not clearing ICR causes QNX to hang as it reads ICR in a loop
              * with disabled interrupts.
@@ -2979,7 +3002,15 @@ static int e1kRegWriteIMS(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint
     IMS |= value;
     E1kLogRel(("E1000: irq enabled, RDH=%x RDT=%x TDH=%x TDT=%x\n", RDH, RDT, TDH, TDT));
     E1kLog(("%s e1kRegWriteIMS: IRQ enabled\n", pThis->szPrf));
-    e1kRaiseInterrupt(pThis, VINF_IOM_R3_MMIO_WRITE, 0);
+    /*
+     * We cannot raise an interrupt here as it will occasionally cause an interrupt storm
+     * in Windows guests (see @bugref{8624}, @bugref{5023}).
+     */
+    if ((ICR & IMS) && !pThis->fLocked)
+    {
+        E1K_INC_ISTAT_CNT(pThis->uStatIntIMS);
+        e1kPostponeInterrupt(pThis, E1K_IMS_INT_DELAY_NS);
+    }
 
     return VINF_SUCCESS;
 }
@@ -6042,8 +6073,8 @@ static void e1kDumpState(PE1KSTATE pThis)
     LogRel(("%s Interrupt attempts: %d\n", pThis->szPrf, pThis->uStatIntTry));
     LogRel(("%s Interrupts raised : %d\n", pThis->szPrf, pThis->uStatInt));
     LogRel(("%s Interrupts lowered: %d\n", pThis->szPrf, pThis->uStatIntLower));
-    LogRel(("%s Interrupts delayed: %d\n", pThis->szPrf, pThis->uStatIntDly));
-    LogRel(("%s Disabled delayed:   %d\n", pThis->szPrf, pThis->uStatDisDly));
+    LogRel(("%s ICR outside ISR   : %d\n", pThis->szPrf, pThis->uStatNoIntICR));
+    LogRel(("%s IMS raised ints   : %d\n", pThis->szPrf, pThis->uStatIntIMS));
     LogRel(("%s Interrupts skipped: %d\n", pThis->szPrf, pThis->uStatIntSkip));
     LogRel(("%s Masked interrupts : %d\n", pThis->szPrf, pThis->uStatIntMasked));
     LogRel(("%s Early interrupts  : %d\n", pThis->szPrf, pThis->uStatIntEarly));
@@ -6084,23 +6115,24 @@ static void e1kDumpState(PE1KSTATE pThis)
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) e1kMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) e1kMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
-    RT_NOREF(iRegion);
-    PE1KSTATE pThis = PDMINS_2_DATA(pPciDev->pDevIns, E1KSTATE*);
+    RT_NOREF(pPciDev, iRegion);
+    PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE *);
     int       rc;
 
     switch (enmType)
     {
         case PCI_ADDRESS_SPACE_IO:
             pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
-            rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pThis->IOPortBase, cb, NULL /*pvUser*/,
+            rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOPortBase, cb, NULL /*pvUser*/,
                                          e1kIOPortOut, e1kIOPortIn, NULL, NULL, "E1000");
             if (pThis->fR0Enabled && RT_SUCCESS(rc))
-                rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pThis->IOPortBase, cb, NIL_RTR0PTR /*pvUser*/,
+                rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOPortBase, cb, NIL_RTR0PTR /*pvUser*/,
                                              "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
             if (pThis->fRCEnabled && RT_SUCCESS(rc))
-                rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pThis->IOPortBase, cb, NIL_RTRCPTR /*pvUser*/,
+                rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOPortBase, cb, NIL_RTRCPTR /*pvUser*/,
                                                "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
             break;
 
@@ -6112,16 +6144,27 @@ static DECLCALLBACK(int) e1kMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhys
              *    Partial reads return all 32 bits of data regardless of the
              *    byte enables.
              */
+#ifdef E1K_WITH_PREREG_MMIO
+            pThis->addrMMReg = GCPhysAddress;
+            if (GCPhysAddress == NIL_RTGCPHYS)
+                rc = VINF_SUCCESS;
+            else
+            {
+                Assert(!(GCPhysAddress & 7));
+                rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
+            }
+#else
             pThis->addrMMReg = GCPhysAddress; Assert(!(GCPhysAddress & 7));
-            rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
+            rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
                                        IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD,
                                        e1kMMIOWrite, e1kMMIORead, "E1000");
             if (pThis->fR0Enabled && RT_SUCCESS(rc))
-                rc = PDMDevHlpMMIORegisterR0(pPciDev->pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
+                rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
                                              "e1kMMIOWrite", "e1kMMIORead");
             if (pThis->fRCEnabled && RT_SUCCESS(rc))
-                rc = PDMDevHlpMMIORegisterRC(pPciDev->pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
+                rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
                                              "e1kMMIOWrite", "e1kMMIORead");
+#endif
             break;
 
         default:
@@ -7115,8 +7158,8 @@ static DECLCALLBACK(void) e1kInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const
     pHlp->pfnPrintf(pHlp, "Interrupt attempts: %d\n", pThis->uStatIntTry);
     pHlp->pfnPrintf(pHlp, "Interrupts raised : %d\n", pThis->uStatInt);
     pHlp->pfnPrintf(pHlp, "Interrupts lowered: %d\n", pThis->uStatIntLower);
-    pHlp->pfnPrintf(pHlp, "Interrupts delayed: %d\n", pThis->uStatIntDly);
-    pHlp->pfnPrintf(pHlp, "Disabled delayed:   %d\n", pThis->uStatDisDly);
+    pHlp->pfnPrintf(pHlp, "ICR outside ISR   : %d\n", pThis->uStatNoIntICR);
+    pHlp->pfnPrintf(pHlp, "IMS raised ints   : %d\n", pThis->uStatIntIMS);
     pHlp->pfnPrintf(pHlp, "Interrupts skipped: %d\n", pThis->uStatIntSkip);
     pHlp->pfnPrintf(pHlp, "Masked interrupts : %d\n", pThis->uStatIntMasked);
     pHlp->pfnPrintf(pHlp, "Early interrupts  : %d\n", pThis->uStatIntEarly);
@@ -7384,7 +7427,7 @@ static DECLCALLBACK(int) e1kR3Destruct(PPDMDEVINS pDevIns)
  * @param   pci         Reference to PCI device structure.
  * @thread  EMT
  */
-static DECLCALLBACK(void) e1kConfigurePciDev(PPCIDEVICE pPciDev, E1KCHIP eChip)
+static DECLCALLBACK(void) e1kConfigurePciDev(PPDMPCIDEV pPciDev, E1KCHIP eChip)
 {
     Assert(eChip < RT_ELEMENTS(g_aChips));
     /* Configure PCI Device, assume 32-bit mode ******************************/
@@ -7640,6 +7683,15 @@ static DECLCALLBACK(int) e1kR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM
     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, E1K_MM_SIZE, PCI_ADDRESS_SPACE_MEM, e1kMap);
     if (RT_FAILURE(rc))
         return rc;
+#ifdef E1K_WITH_PREREG_MMIO
+    rc = PDMDevHlpMMIOExPreRegister(pDevIns, 0, E1K_MM_SIZE, IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD, "E1000",
+                                    NULL        /*pvUserR3*/, e1kMMIOWrite, e1kMMIORead, NULL /*pfnFillR3*/,
+                                    NIL_RTR0PTR /*pvUserR0*/, pThis->fR0Enabled ? "e1kMMIOWrite" : NULL,
+                                    pThis->fR0Enabled ? "e1kMMIORead" : NULL, NULL /*pszFillR0*/,
+                                    NIL_RTRCPTR /*pvUserRC*/, pThis->fRCEnabled ? "e1kMMIOWrite" : NULL,
+                                    pThis->fRCEnabled ? "e1kMMIORead" : NULL, NULL /*pszFillRC*/);
+    AssertLogRelRCReturn(rc, rc);
+#endif
     /* Map our registers to IO space (region 2, see e1kConfigurePCI) */
     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, E1K_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, e1kMap);
     if (RT_FAILURE(rc))
@@ -7833,10 +7885,10 @@ static DECLCALLBACK(int) e1kR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatInt,               STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatInt",                           "/Devices/E1k%d/uStatInt", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTry,            STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntTry",                        "/Devices/E1k%d/uStatIntTry", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntLower,          STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntLower",                      "/Devices/E1k%d/uStatIntLower", iInstance);
-    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntDly,            STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntDly",                        "/Devices/E1k%d/uStatIntDly", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatNoIntICR,          STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatNoIntICR",                      "/Devices/E1k%d/uStatNoIntICR", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->iStatIntLost,           STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "iStatIntLost",                       "/Devices/E1k%d/iStatIntLost", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->iStatIntLostOne,        STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "iStatIntLostOne",                    "/Devices/E1k%d/iStatIntLostOne", iInstance);
-    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDisDly,            STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatDisDly",                        "/Devices/E1k%d/uStatDisDly", iInstance);
+    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntIMS,            STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntIMS",                        "/Devices/E1k%d/uStatIntIMS", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntSkip,           STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntSkip",                       "/Devices/E1k%d/uStatIntSkip", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntLate,           STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntLate",                       "/Devices/E1k%d/uStatIntLate", iInstance);
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntMasked,         STAMTYPE_U32,     STAMVISIBILITY_ALWAYS, STAMUNIT_NS,             "uStatIntMasked",                     "/Devices/E1k%d/uStatIntMasked", iInstance);
diff --git a/src/VBox/Devices/Network/DevPCNet.cpp b/src/VBox/Devices/Network/DevPCNet.cpp
index be0ed07..c0097d3 100644
--- a/src/VBox/Devices/Network/DevPCNet.cpp
+++ b/src/VBox/Devices/Network/DevPCNet.cpp
@@ -246,7 +246,7 @@
 /**
  * PCNET state.
  *
- * @extends     PCIDEVICE
+ * @extends     PDMPCIDEV
  * @implements  PDMIBASE
  * @implements  PDMINETWORKDOWN
  * @implements  PDMINETWORKCONFIG
@@ -254,7 +254,7 @@
  */
 typedef struct PCNETSTATE
 {
-    PCIDEVICE                           PciDev;
+    PDMPCIDEV                           PciDev;
 
     /** Pointer to the device instance - R3. */
     PPDMDEVINSR3                        pDevInsR3;
@@ -3866,12 +3866,11 @@ static DECLCALLBACK(void) pcnetTimerRestore(PPDMDEVINS pDevIns, PTMTIMER pTimer,
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP, For the PC-NET I/O Ports.}
  */
-static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
+static DECLCALLBACK(int) pcnetIOPortMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
                                         RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, cb, enmType);
     int         rc;
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
     RTIOPORT    Port    = (RTIOPORT)GCPhysAddress;
     PPCNETSTATE pThis   = PCIDEV_2_PCNETSTATE(pPciDev);
 
@@ -3918,7 +3917,7 @@ static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRe
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP, For the PC-Net MMIO region.}
  */
-static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
+static DECLCALLBACK(int) pcnetMMIOMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
                                       RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, cb, enmType);
@@ -3929,7 +3928,7 @@ static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegi
     Assert(cb >= PCNET_PNPMMIO_SIZE);
 
     /* We use the assigned size here, because we only support page aligned MMIO ranges. */
-    rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pThis,
+    rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, pThis,
                                IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
                                pcnetMMIOWrite, pcnetMMIORead, "PCNet");
     if (RT_FAILURE(rc))
@@ -4291,7 +4290,7 @@ static DECLCALLBACK(int) pcnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     {
         /* older saved states contain the shared memory region which was never used for ages. */
         void *pvSharedMMIOR3;
-        rc = PDMDevHlpMMIO2Register(pDevIns, 2, _512K, 0, (void **)&pvSharedMMIOR3, "PCNetSh");
+        rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 2, _512K, 0, (void **)&pvSharedMMIOR3, "PCNetSh");
         if (RT_FAILURE(rc))
             rc = PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                      N_("Failed to allocate the dummy shmem region for the PCNet device"));
@@ -4417,7 +4416,7 @@ static DECLCALLBACK(int) pcnetLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     if (pThis->fSharedRegion)
     {
         /* drop this dummy region */
-        rc = PDMDevHlpMMIO2Deregister(pDevIns, 2);
+        rc = PDMDevHlpMMIOExDeregister(pDevIns, NULL, 2);
         pThis->fSharedRegion = false;
     }
     return rc;
@@ -4954,33 +4953,33 @@ static DECLCALLBACK(int) pcnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGM
     /* PCI Device */
     PCIDevSetVendorId(&pThis->PciDev, 0x1022);
     PCIDevSetDeviceId(&pThis->PciDev, 0x2000);
-    pThis->PciDev.config[0x04] = 0x07; /* command */
-    pThis->PciDev.config[0x05] = 0x00;
-    pThis->PciDev.config[0x06] = 0x80; /* status */
-    pThis->PciDev.config[0x07] = 0x02;
-    pThis->PciDev.config[0x08] = pThis->fAm79C973 ? 0x40 : 0x10; /* revision */
-    pThis->PciDev.config[0x09] = 0x00;
-    pThis->PciDev.config[0x0a] = 0x00; /* ethernet network controller */
-    pThis->PciDev.config[0x0b] = 0x02;
-    pThis->PciDev.config[0x0e] = 0x00; /* header_type */
-
-    pThis->PciDev.config[0x10] = 0x01; /* IO Base */
-    pThis->PciDev.config[0x11] = 0x00;
-    pThis->PciDev.config[0x12] = 0x00;
-    pThis->PciDev.config[0x13] = 0x00;
-    pThis->PciDev.config[0x14] = 0x00; /* MMIO Base */
-    pThis->PciDev.config[0x15] = 0x00;
-    pThis->PciDev.config[0x16] = 0x00;
-    pThis->PciDev.config[0x17] = 0x00;
+    pThis->PciDev.abConfig[0x04] = 0x07; /* command */
+    pThis->PciDev.abConfig[0x05] = 0x00;
+    pThis->PciDev.abConfig[0x06] = 0x80; /* status */
+    pThis->PciDev.abConfig[0x07] = 0x02;
+    pThis->PciDev.abConfig[0x08] = pThis->fAm79C973 ? 0x40 : 0x10; /* revision */
+    pThis->PciDev.abConfig[0x09] = 0x00;
+    pThis->PciDev.abConfig[0x0a] = 0x00; /* ethernet network controller */
+    pThis->PciDev.abConfig[0x0b] = 0x02;
+    pThis->PciDev.abConfig[0x0e] = 0x00; /* header_type */
+
+    pThis->PciDev.abConfig[0x10] = 0x01; /* IO Base */
+    pThis->PciDev.abConfig[0x11] = 0x00;
+    pThis->PciDev.abConfig[0x12] = 0x00;
+    pThis->PciDev.abConfig[0x13] = 0x00;
+    pThis->PciDev.abConfig[0x14] = 0x00; /* MMIO Base */
+    pThis->PciDev.abConfig[0x15] = 0x00;
+    pThis->PciDev.abConfig[0x16] = 0x00;
+    pThis->PciDev.abConfig[0x17] = 0x00;
 
     /* subsystem and subvendor IDs */
-    pThis->PciDev.config[0x2c] = 0x22; /* subsystem vendor id */
-    pThis->PciDev.config[0x2d] = 0x10;
-    pThis->PciDev.config[0x2e] = 0x00; /* subsystem id */
-    pThis->PciDev.config[0x2f] = 0x20;
-    pThis->PciDev.config[0x3d] = 1;    /* interrupt pin 0 */
-    pThis->PciDev.config[0x3e] = 0x06;
-    pThis->PciDev.config[0x3f] = 0xff;
+    pThis->PciDev.abConfig[0x2c] = 0x22; /* subsystem vendor id */
+    pThis->PciDev.abConfig[0x2d] = 0x10;
+    pThis->PciDev.abConfig[0x2e] = 0x00; /* subsystem id */
+    pThis->PciDev.abConfig[0x2f] = 0x20;
+    pThis->PciDev.abConfig[0x3d] = 1;    /* interrupt pin 0 */
+    pThis->PciDev.abConfig[0x3e] = 0x06;
+    pThis->PciDev.abConfig[0x3f] = 0xff;
 
     /*
      * We use our own critical section (historical reasons).
diff --git a/src/VBox/Devices/Network/DevVirtioNet.cpp b/src/VBox/Devices/Network/DevVirtioNet.cpp
index 61f0c2d..d294a90 100644
--- a/src/VBox/Devices/Network/DevVirtioNet.cpp
+++ b/src/VBox/Devices/Network/DevVirtioNet.cpp
@@ -1772,10 +1772,11 @@ static DECLCALLBACK(int) vnetLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) vnetMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) vnetMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
-    RT_NOREF(iRegion);
-    PVNETSTATE pThis = PDMINS_2_DATA(pPciDev->pDevIns, PVNETSTATE);
+    RT_NOREF(pPciDev, iRegion);
+    PVNETSTATE pThis = PDMINS_2_DATA(pDevIns, PVNETSTATE);
     int       rc;
 
     if (enmType != PCI_ADDRESS_SPACE_IO)
@@ -1786,16 +1787,16 @@ static DECLCALLBACK(int) vnetMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhy
     }
 
     pThis->VPCI.IOPortBase = (RTIOPORT)GCPhysAddress;
-    rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pThis->VPCI.IOPortBase,
+    rc = PDMDevHlpIOPortRegister(pDevIns, pThis->VPCI.IOPortBase,
                                  cb, 0, vnetIOPortOut, vnetIOPortIn,
                                  NULL, NULL, "VirtioNet");
 #ifdef VNET_GC_SUPPORT
     AssertRCReturn(rc, rc);
-    rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pThis->VPCI.IOPortBase,
+    rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->VPCI.IOPortBase,
                                    cb, 0, "vnetIOPortOut", "vnetIOPortIn",
                                    NULL, NULL, "VirtioNet");
     AssertRCReturn(rc, rc);
-    rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pThis->VPCI.IOPortBase,
+    rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->VPCI.IOPortBase,
                                    cb, 0, "vnetIOPortOut", "vnetIOPortIn",
                                    NULL, NULL, "VirtioNet");
 #endif
diff --git a/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c b/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c
index 7d4afbf..a6a6c69 100644
--- a/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c
+++ b/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c
@@ -202,6 +202,7 @@ tcpip_input(struct pbuf *p, struct netif *inp)
   }
   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
   if (msg == NULL) {
+    LogRel2(("TCPIP_MSG_INPKT alloc failed\n"));
     return ERR_MEM;
   }
 
@@ -209,6 +210,7 @@ tcpip_input(struct pbuf *p, struct netif *inp)
   msg->msg.inp.p = p;
   msg->msg.inp.netif = inp;
   if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
+    LogRel2(("tcpip trypost failed\n"));
     memp_free(MEMP_TCPIP_MSG_INPKT, msg);
     return ERR_MEM;
   }
diff --git a/src/VBox/Devices/Network/lwip-new/src/core/tcp_in.c b/src/VBox/Devices/Network/lwip-new/src/core/tcp_in.c
index 51de9c0..f50e652 100644
--- a/src/VBox/Devices/Network/lwip-new/src/core/tcp_in.c
+++ b/src/VBox/Devices/Network/lwip-new/src/core/tcp_in.c
@@ -83,6 +83,9 @@ static struct pbuf *recv_data;
 
 struct tcp_pcb *tcp_input_pcb;
 
+static int fin2debug;
+#define FIN2DEBUG(args) do { if (fin2debug) LogRel2(args); } while (0)
+
 /* Forward declarations. */
 static void tcp_input1(struct pbuf *p, struct netif *inp);
 static err_t tcp_process(struct tcp_pcb *pcb);
@@ -196,6 +199,11 @@ tcp_input1(struct pbuf *p, struct netif *inp)
   flags = TCPH_FLAGS(tcphdr);
   tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
 
+  /* XXX: temporary instrumentation for ticketref:14748 */
+  fin2debug = 0;
+  if ((flags & TCP_FIN) && tcphdr->dest == 8080)
+      fin2debug = 1;
+
   /* Demultiplex an incoming segment. First, we check if it is destined
      for an active connection. */
   prev = NULL;
@@ -337,6 +345,16 @@ tcp_input1(struct pbuf *p, struct netif *inp)
 #endif /* TCP_DEBUG */
 #endif /* TCP_INPUT_DEBUG */
 
+    if (fin2debug) {
+        if (pcb->state != FIN_WAIT_2) {
+            FIN2DEBUG(("> ignoring pcb->state = %d\n", pcb->state));
+            fin2debug = 0;
+        }
+        else {
+            FIN2DEBUG(("> fin2debug: tcplen = %d\n", tcplen));
+        }
+    }
+
     /* Set up a tcp_seg structure. */
     inseg.next = NULL;
     inseg.len = p->tot_len;
@@ -352,6 +370,7 @@ tcp_input1(struct pbuf *p, struct netif *inp)
 
     /* If there is data which was previously "refused" by upper layer */
     if (pcb->refused_data != NULL) {
+      FIN2DEBUG(("pcb->refused_data != NULL\n")); /* very unlikely */
       if ((tcp_process_refused_data(pcb) == ERR_ABRT) ||
         ((pcb->refused_data != NULL) && (tcplen > 0))) {
         /* pcb has been aborted or refused data is still refused and the new
@@ -1042,7 +1061,8 @@ tcp_process(struct tcp_pcb *pcb)
   case FIN_WAIT_1:
     tcp_receive(pcb);
     if (recv_flags & TF_GOT_FIN) {
-      if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
+      if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
+          pcb->unsent == NULL) {
         LWIP_DEBUGF(TCP_DEBUG,
           ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
         tcp_ack_now(pcb);
@@ -1054,13 +1074,15 @@ tcp_process(struct tcp_pcb *pcb)
         tcp_ack_now(pcb);
         pcb->state = CLOSING;
       }
-    } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
+    } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
+               pcb->unsent == NULL) {
       pcb->state = FIN_WAIT_2;
     }
     break;
   case FIN_WAIT_2:
     tcp_receive(pcb);
     if (recv_flags & TF_GOT_FIN) {
+      FIN2DEBUG(("TF_GOT_FIN\n"));
       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
       tcp_ack_now(pcb);
       tcp_pcb_purge(pcb);
@@ -1068,10 +1090,12 @@ tcp_process(struct tcp_pcb *pcb)
       pcb->state = TIME_WAIT;
       TCP_REG(&tcp_tw_pcbs, pcb);
     }
+    else
+        FIN2DEBUG(("not TF_GOT_FIN?!\n"));
     break;
   case CLOSING:
     tcp_receive(pcb);
-    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
+    if (flags & TCP_ACK && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
       tcp_pcb_purge(pcb);
       TCP_RMV_ACTIVE(pcb);
@@ -1081,7 +1105,7 @@ tcp_process(struct tcp_pcb *pcb)
     break;
   case LAST_ACK:
     tcp_receive(pcb);
-    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
+    if (flags & TCP_ACK && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
       /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
       recv_flags |= TF_CLOSED;
@@ -1459,6 +1483,7 @@ tcp_receive(struct tcp_pcb *pcb)
     /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
           if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
     if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
+      FIN2DEBUG(("trim left: seqno %u, rcv_nxt %u\n", seqno, pcb->rcv_nxt));
       /* Trimming the first edge is done by pushing the payload
          pointer in the pbuf downwards. This is somewhat tricky since
          we do not want to discard the full contents of the pbuf up to
@@ -1528,12 +1553,14 @@ tcp_receive(struct tcp_pcb *pcb)
            we have to trim the end of the segment and update rcv_nxt
            and pass the data to the application. */
         tcplen = TCP_TCPLEN(&inseg);
+        FIN2DEBUG(("in-sequence FIN %u, new tcplen = %u\n", seqno, tcplen));
 
         if (tcplen > pcb->rcv_wnd) {
           LWIP_DEBUGF(TCP_INPUT_DEBUG, 
                       ("tcp_receive: other end overran receive window"
                        "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
                        seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
+          FIN2DEBUG(("tcplen %u > rcv_wnd %u\n", tcplen, pcb->rcv_wnd));
           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
             /* Must remove the FIN from the header as we're trimming 
              * that byte of sequence-space from the packet */
@@ -1554,6 +1581,7 @@ tcp_receive(struct tcp_pcb *pcb)
            - FIN has been received or
            - inseq overlaps with ooseq */
         if (pcb->ooseq != NULL) {
+          FIN2DEBUG(("ooseq != NULL\n")); /* very unlikely */
           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
             LWIP_DEBUGF(TCP_INPUT_DEBUG, 
                         ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
@@ -1630,6 +1658,9 @@ tcp_receive(struct tcp_pcb *pcb)
           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
           recv_flags |= TF_GOT_FIN;
         }
+        else {
+            FIN2DEBUG(("flags 0x%x?!\n", TCPH_FLAGS(inseg.tcphdr)));
+        }
 
 #if TCP_QUEUE_OOSEQ
         /* We now check if we have segments on the ->ooseq queue that
diff --git a/src/VBox/Devices/Network/slirp/slirp.c b/src/VBox/Devices/Network/slirp/slirp.c
index ef6c5ca..5014d39 100644
--- a/src/VBox/Devices/Network/slirp/slirp.c
+++ b/src/VBox/Devices/Network/slirp/slirp.c
@@ -1127,7 +1127,11 @@ void slirp_select_poll(PNATState pData, struct pollfd *polls, int ndfs)
             }
 
             /* if socket freed ''so'' is PHANTOM and next socket isn't points on it */
-            if (so_next->so_prev == so)
+            if (so_next->so_prev != so)
+            {
+                CONTINUE(tcp);
+            }
+            else
             {
                 /* mark the socket for termination _after_ it was drained */
                 so->so_close = 1;
@@ -1138,9 +1142,6 @@ void slirp_select_poll(PNATState pData, struct pollfd *polls, int ndfs)
                     sofcantsendmore(so);
 #endif
             }
-            if (so_next->so_prev == so)
-                so->fUnderPolling = 0;
-            CONTINUE(tcp);
         }
 
         /*
diff --git a/src/VBox/Devices/Network/slirp/slirp.h b/src/VBox/Devices/Network/slirp/slirp.h
index d6e1b98..11e8b0f 100644
--- a/src/VBox/Devices/Network/slirp/slirp.h
+++ b/src/VBox/Devices/Network/slirp/slirp.h
@@ -81,25 +81,32 @@ typedef int socklen_t;
 /* We don't want the errno.h versions of these error defines. */
 # if defined(_MSC_VER) && _MSC_VER >= 1600
 #  include <errno.h>
-#  undef EWOULDBLOCK
-#  undef EINPROGRESS
-#  undef ENOTCONN
-#  undef EHOSTUNREACH
-#  undef ENETUNREACH
 #  undef ECONNREFUSED
 #  undef ECONNRESET
 #  undef EHOSTDOWN
+#  undef EHOSTUNREACH
+#  undef EINPROGRESS
 #  undef ENETDOWN
+#  undef ENETUNREACH
+#  undef ENOTCONN
+#  undef ESHUTDOWN
+#  undef EWOULDBLOCK
 # endif
-# define EWOULDBLOCK WSAEWOULDBLOCK
-# define EINPROGRESS WSAEINPROGRESS
-# define ENOTCONN WSAENOTCONN
-# define EHOSTUNREACH WSAEHOSTUNREACH
-# define ENETUNREACH WSAENETUNREACH
 # define ECONNREFUSED WSAECONNREFUSED
 # define ECONNRESET WSAECONNRESET
 # define EHOSTDOWN WSAEHOSTDOWN
+# define EHOSTUNREACH WSAEHOSTUNREACH
+# define EINPROGRESS WSAEINPROGRESS
 # define ENETDOWN WSAENETDOWN
+# define ENETUNREACH WSAENETUNREACH
+# define ENOTCONN WSAENOTCONN
+# define ESHUTDOWN WSAESHUTDOWN
+# define EWOULDBLOCK WSAEWOULDBLOCK
+
+/* standard names for the shutdown() "how" argument */
+#define SHUT_RD SD_RECEIVE
+#define SHUT_WR SD_SEND
+#define SHUT_RDWR SD_BOTH
 
 typedef uint8_t u_int8_t;
 typedef uint16_t u_int16_t;
diff --git a/src/VBox/Devices/Network/slirp/socket.c b/src/VBox/Devices/Network/slirp/socket.c
index 813f4c1..9ed8abf 100644
--- a/src/VBox/Devices/Network/slirp/socket.c
+++ b/src/VBox/Devices/Network/slirp/socket.c
@@ -330,6 +330,18 @@ soread(PNATState pData, struct socket *so)
     Log2(("%s: so = %R[natsock] so->so_snd = %R[sbuf]\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, so, sb));
     if (nn <= 0)
     {
+#ifdef RT_OS_WINDOWS
+        /*
+         * Windows reports ESHUTDOWN after SHUT_RD (SD_RECEIVE)
+         * instead of just returning EOF indication.
+         */
+        if (nn < 0 && sockerr == ESHUTDOWN)
+        {
+            nn = 0;
+            sockerr = 0;
+        }
+#endif
+
         if (nn == 0) /* XXX: should this be inside #if defined(RT_OS_WINDOWS)? */
         {
             /*
@@ -375,7 +387,10 @@ soread(PNATState pData, struct socket *so)
             if (!sockerr && !shuterr && !fUninitializedTemplate)
                 tcp_sockclosed(pData, sototcpcb(so));
             else
+            {
+                LogRel2(("NAT: sockerr %d, shuterr %d - %R[natsock]\n", sockerr, shuterr, so));
                 tcp_drop(pData, sototcpcb(so), sockerr);
+            }
             SOCKET_UNLOCK(so);
             STAM_PROFILE_STOP(&pData->StatIOread, a);
             return -1;
@@ -1114,16 +1129,26 @@ sofcantrcvmore(struct  socket *so)
         /*
          * If remote closes first and then sends an RST, the recv() in
          * soread() will keep reporting EOF without any error
-         * indication, so we must also check if shutdown() succeeds
-         * here.
+         * indication.  As far as I can tell the only way to detect
+         * this on Linux is to check if shutdown() succeeds here (but
+         * see below).
+         * 
+         * OTOH on OS X shutdown() "helpfully" checks if remote has
+         * already closed and then always returns ENOTCONN
+         * immediately.
          */
-        int status = shutdown(so->s, 0);
+        int status = shutdown(so->s, SHUT_RD);
+#if defined(RT_OS_LINUX)
         if (status < 0)
             err = errno;
+#else
+        RT_NOREF(status);
+#endif
     }
     so->so_state &= ~(SS_ISFCONNECTING);
     if (so->so_state & SS_FCANTSENDMORE)
     {
+#if defined(RT_OS_LINUX)
         /*
          * If we have closed first, and remote closes, shutdown will
          * return ENOTCONN, but this is expected.  Don't tell the
@@ -1131,6 +1156,7 @@ sofcantrcvmore(struct  socket *so)
          */
         if (err == ENOTCONN)
             err = 0;
+#endif
         so->so_state = SS_NOFDREF; /* Don't select it */
                                    /* XXX close() here as well? */
     }
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
index cc9696f..faf7712 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
@@ -1115,7 +1115,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
 
 section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
 _bios_cvs_version_string:                    ; 0xf0d8e LB 0x12
-    db  'VirtualBox 5.1.8', 000h, 000h
+    db  'VirtualBox 5.1.10', 000h
 _bios_prefix_string:                         ; 0xf0da0 LB 0x8
     db  'BIOS: ', 000h, 000h
 _isotag:                                     ; 0xf0da8 LB 0x6
@@ -17798,4 +17798,4 @@ biosorg_check_before_or_at_0FFEEh:           ; 0xfff80 LB 0x70
     db  'XM'
 cpu_reset:                                   ; 0xffff0 LB 0x10
     jmp far 0f000h:0e05bh                     ; ea 5b e0 00 f0
-    db  030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 083h
+    db  030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 05ah
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
index a11e98c..ee27e2d 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
@@ -1 +1 @@
-746d52a3293874115332c075b679f9cf *VBoxPcBios286.rom
+dc5a9dd4637c5e3d9e8e19109969769e *VBoxPcBios286.rom
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
index 2a45899..1846f9b 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
@@ -1078,7 +1078,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
 
 section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
 _bios_cvs_version_string:                    ; 0xf0d8e LB 0x12
-    db  'VirtualBox 5.1.8', 000h, 000h
+    db  'VirtualBox 5.1.10', 000h
 _bios_prefix_string:                         ; 0xf0da0 LB 0x8
     db  'BIOS: ', 000h, 000h
 _isotag:                                     ; 0xf0da8 LB 0x6
@@ -17197,4 +17197,4 @@ biosorg_check_before_or_at_0FFEEh:           ; 0xfff80 LB 0x70
     db  'XM'
 cpu_reset:                                   ; 0xffff0 LB 0x10
     jmp far 0f000h:0e05bh                     ; ea 5b e0 00 f0
-    db  030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 014h
+    db  030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 0ebh
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
index e375c28..fdb5bc0 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
@@ -1 +1 @@
-f74c607b2fee27c05848ec35b9ee4e54 *VBoxPcBios386.rom
+e2928263872d86cfe6b78376a774a4db *VBoxPcBios386.rom
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
index de585f2..5f31855 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
@@ -1115,7 +1115,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
 
 section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
 _bios_cvs_version_string:                    ; 0xf0d8e LB 0x12
-    db  'VirtualBox 5.1.8', 000h, 000h
+    db  'VirtualBox 5.1.10', 000h
 _bios_prefix_string:                         ; 0xf0da0 LB 0x8
     db  'BIOS: ', 000h, 000h
 _isotag:                                     ; 0xf0da8 LB 0x6
@@ -18273,4 +18273,4 @@ biosorg_check_before_or_at_0FFEEh:           ; 0xfff80 LB 0x70
     db  'XM'
 cpu_reset:                                   ; 0xffff0 LB 0x10
     jmp far 0f000h:0e05bh                     ; ea 5b e0 00 f0
-    db  030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fbh, 031h
+    db  030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fbh, 008h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
index 49287c3..a77cbed 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
@@ -1 +1 @@
-310200850223ce2fb16f39636fb9125f *VBoxPcBios8086.rom
+e2457d5408fa7e98ed68b4633aceeee7 *VBoxPcBios8086.rom
diff --git a/src/VBox/Devices/PC/DevACPI.cpp b/src/VBox/Devices/PC/DevACPI.cpp
index 1ec9564..d0cf09e 100644
--- a/src/VBox/Devices/PC/DevACPI.cpp
+++ b/src/VBox/Devices/PC/DevACPI.cpp
@@ -281,7 +281,7 @@ enum
  */
 typedef struct ACPIState
 {
-    PCIDevice           dev;
+    PDMPCIDEV           dev;
     /** Critical section protecting the ACPI state. */
     PDMCRITSECT         CritSect;
 
@@ -792,8 +792,8 @@ DECLINLINE(bool) gpe0_level(ACPIState *pThis)
 DECLINLINE(bool) smbus_level(ACPIState *pThis)
 {
     return    (pThis->u8SMBusHstCnt & SMBHSTCNT_INTEREN)
-           && (pThis->dev.config[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
-           && (pThis->dev.config[SMBHSTCFG] & SMBHSTCFG_INTRSEL) == SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT
+           && (pThis->dev.abConfig[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
+           && (pThis->dev.abConfig[SMBHSTCFG] & SMBHSTCFG_INTRSEL) == SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT
            && (pThis->u8SMBusHstSts & SMBHSTSTS_INT_MASK);
 }
 
@@ -1926,10 +1926,10 @@ PDMBOTHCBDECL(int) acpiR3DchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Po
  */
 static void acpiR3PmPCIBIOSFake(ACPIState *pThis)
 {
-    pThis->dev.config[PMBA  ] = pThis->uPmIoPortBase | 1; /* PMBA, PM base address, bit 0 marks it as IO range */
-    pThis->dev.config[PMBA+1] = pThis->uPmIoPortBase >> 8;
-    pThis->dev.config[PMBA+2] = 0x00;
-    pThis->dev.config[PMBA+3] = 0x00;
+    pThis->dev.abConfig[PMBA  ] = pThis->uPmIoPortBase | 1; /* PMBA, PM base address, bit 0 marks it as IO range */
+    pThis->dev.abConfig[PMBA+1] = pThis->uPmIoPortBase >> 8;
+    pThis->dev.abConfig[PMBA+2] = 0x00;
+    pThis->dev.abConfig[PMBA+3] = 0x00;
 }
 
 /**
@@ -2227,15 +2227,15 @@ PDMBOTHCBDECL(int) acpiR3SMBusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Po
  */
 static void acpiR3SMBusPCIBIOSFake(ACPIState *pThis)
 {
-    pThis->dev.config[SMBBA  ] = pThis->uSMBusIoPortBase | 1; /* SMBBA, SMBus base address, bit 0 marks it as IO range */
-    pThis->dev.config[SMBBA+1] = pThis->uSMBusIoPortBase >> 8;
-    pThis->dev.config[SMBBA+2] = 0x00;
-    pThis->dev.config[SMBBA+3] = 0x00;
-    pThis->dev.config[SMBHSTCFG] = SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT | SMBHSTCFG_SMB_HST_EN; /* SMBHSTCFG */
-    pThis->dev.config[SMBSLVC] = 0x00; /* SMBSLVC */
-    pThis->dev.config[SMBSHDW1] = 0x00; /* SMBSHDW1 */
-    pThis->dev.config[SMBSHDW2] = 0x00; /* SMBSHDW2 */
-    pThis->dev.config[SMBREV] = 0x00; /* SMBREV */
+    pThis->dev.abConfig[SMBBA  ] = pThis->uSMBusIoPortBase | 1; /* SMBBA, SMBus base address, bit 0 marks it as IO range */
+    pThis->dev.abConfig[SMBBA+1] = pThis->uSMBusIoPortBase >> 8;
+    pThis->dev.abConfig[SMBBA+2] = 0x00;
+    pThis->dev.abConfig[SMBBA+3] = 0x00;
+    pThis->dev.abConfig[SMBHSTCFG] = SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT | SMBHSTCFG_SMB_HST_EN; /* SMBHSTCFG */
+    pThis->dev.abConfig[SMBSLVC] = 0x00; /* SMBSLVC */
+    pThis->dev.abConfig[SMBSHDW1] = 0x00; /* SMBSHDW1 */
+    pThis->dev.abConfig[SMBSHDW2] = 0x00; /* SMBSHDW2 */
+    pThis->dev.abConfig[SMBREV] = 0x00; /* SMBREV */
 }
 
 /**
@@ -3265,22 +3265,21 @@ static int acpiR3PlantTables(ACPIState *pThis)
 /**
  * @callback_method_impl{FNPCICONFIGREAD}
  */
-static DECLCALLBACK(uint32_t) acpiR3PciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
+static DECLCALLBACK(uint32_t) acpiR3PciConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t Address, unsigned cb)
 {
-    PPDMDEVINS pDevIns = pPciDev->pDevIns;
     ACPIState *pThis   = PDMINS_2_DATA(pDevIns, ACPIState *);
 
     Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
-    return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
+    return pThis->pfnAcpiPciConfigRead(pDevIns, pPciDev, Address, cb);
 }
 
 /**
  * @callback_method_impl{FNPCICONFIGWRITE}
  */
-static DECLCALLBACK(void) acpiR3PciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
+static DECLCALLBACK(void) acpiR3PciConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t Address,
+                                               uint32_t u32Value, unsigned cb)
 {
-    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
-    ACPIState  *pThis   = PDMINS_2_DATA(pDevIns, ACPIState *);
+    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
 
     Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
     DEVACPI_LOCK_R3(pThis);
@@ -3291,7 +3290,7 @@ static DECLCALLBACK(void) acpiR3PciConfigWrite(PPCIDEVICE pPciDev, uint32_t Addr
         u32Value = SCI_INT;
     }
 
-    pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
+    pThis->pfnAcpiPciConfigWrite(pDevIns, pPciDev, Address, u32Value, cb);
 
     /* Assume that the base address is only changed when the corresponding
      * hardware functionality is disabled. The IO region is mapped when the
@@ -3301,7 +3300,7 @@ static DECLCALLBACK(void) acpiR3PciConfigWrite(PPCIDEVICE pPciDev, uint32_t Addr
     {
         RTIOPORT NewIoPortBase = 0;
         /* Check Power Management IO Space Enable (PMIOSE) bit */
-        if (pPciDev->config[PMREGMISC] & 0x01)
+        if (pPciDev->abConfig[PMREGMISC] & 0x01)
         {
             NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, PMBA);
             NewIoPortBase &= 0xffc0;
@@ -3315,7 +3314,7 @@ static DECLCALLBACK(void) acpiR3PciConfigWrite(PPCIDEVICE pPciDev, uint32_t Addr
     {
         RTIOPORT NewIoPortBase = 0;
         /* Check SMBus Controller Host Interface Enable (SMB_HST_EN) bit */
-        if (pPciDev->config[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
+        if (pPciDev->abConfig[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
         {
             NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, SMBBA);
             NewIoPortBase &= 0xfff0;
diff --git a/src/VBox/Devices/PC/DevLPC.cpp b/src/VBox/Devices/PC/DevLPC.cpp
index de7ec33..21c0a52 100644
--- a/src/VBox/Devices/PC/DevLPC.cpp
+++ b/src/VBox/Devices/PC/DevLPC.cpp
@@ -64,7 +64,7 @@
 typedef struct
 {
     /** PCI device structure. */
-    PCIDEVICE      dev;
+    PDMPCIDEV      dev;
 
     /** Pointer to the device instance. - R3 ptr. */
     PPDMDEVINSR3   pDevIns;
@@ -189,11 +189,11 @@ static DECLCALLBACK(void) lpcInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const
     LPCState   *pThis = PDMINS_2_DATA(pDevIns, LPCState *);
     LogFlow(("lpcInfo: \n"));
 
-    if (pThis->dev.config[0xde] == 0xbe && pThis->dev.config[0xad] == 0xef)
+    if (pThis->dev.abConfig[0xde] == 0xbe && pThis->dev.abConfig[0xad] == 0xef)
         pHlp->pfnPrintf(pHlp, "APIC backdoor activated\n");
     else
         pHlp->pfnPrintf(pHlp, "APIC backdoor closed: %02x %02x\n",
-                        pThis->dev.config[0xde], pThis->dev.config[0xad]);
+                        pThis->dev.abConfig[0xde], pThis->dev.abConfig[0xad]);
 
 
     for (int iLine = 0; iLine < 8; ++iLine)
@@ -245,40 +245,40 @@ static DECLCALLBACK(int) lpcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
     /* See p. 427 of ICH9 specification for register description */
 
     /* 40h - 43h PMBASE 40-43 ACPI Base Address */
-    pThis->dev.config[0x40] = 0x01; /* IO space */
-    pThis->dev.config[0x41] = 0x80; /* base address / 128, see DevACPI.cpp */
+    pThis->dev.abConfig[0x40] = 0x01; /* IO space */
+    pThis->dev.abConfig[0x41] = 0x80; /* base address / 128, see DevACPI.cpp */
 
     /* 44h       ACPI_CNTL    ACPI Control */
-    pThis->dev.config[0x44] = 0x00 | (1<<7); /* SCI is IRQ9, ACPI enabled */
+    pThis->dev.abConfig[0x44] = 0x00 | (1<<7); /* SCI is IRQ9, ACPI enabled */
     /* 48h–4Bh   GPIOBASE     GPIO Base Address */
 
     /* 4C        GC           GPIO Control */
-    pThis->dev.config[0x4c] = 0x4d;
+    pThis->dev.abConfig[0x4c] = 0x4d;
     /* ???? */
-    pThis->dev.config[0x4e] = 0x03;
-    pThis->dev.config[0x4f] = 0x00;
+    pThis->dev.abConfig[0x4e] = 0x03;
+    pThis->dev.abConfig[0x4f] = 0x00;
 
     /* 60h-63h PIRQ[n]_ROUT PIRQ[A-D] Routing Control */
-    pThis->dev.config[0x60] = 0x0b; /* PCI A -> IRQ 11 */
-    pThis->dev.config[0x61] = 0x09; /* PCI B -> IRQ 9  */
-    pThis->dev.config[0x62] = 0x0b; /* PCI C -> IRQ 11 */
-    pThis->dev.config[0x63] = 0x09; /* PCI D -> IRQ 9  */
+    pThis->dev.abConfig[0x60] = 0x0b; /* PCI A -> IRQ 11 */
+    pThis->dev.abConfig[0x61] = 0x09; /* PCI B -> IRQ 9  */
+    pThis->dev.abConfig[0x62] = 0x0b; /* PCI C -> IRQ 11 */
+    pThis->dev.abConfig[0x63] = 0x09; /* PCI D -> IRQ 9  */
 
     /* 64h SIRQ_CNTL Serial IRQ Control 10h R/W, RO */
-    pThis->dev.config[0x64] = 0x10;
+    pThis->dev.abConfig[0x64] = 0x10;
 
     /* 68h-6Bh PIRQ[n]_ROUT PIRQ[E-H] Routing Control  */
-    pThis->dev.config[0x68] = 0x80;
-    pThis->dev.config[0x69] = 0x80;
-    pThis->dev.config[0x6A] = 0x80;
-    pThis->dev.config[0x6B] = 0x80;
+    pThis->dev.abConfig[0x68] = 0x80;
+    pThis->dev.abConfig[0x69] = 0x80;
+    pThis->dev.abConfig[0x6A] = 0x80;
+    pThis->dev.abConfig[0x6B] = 0x80;
 
     /* 6C-6Dh     LPC_IBDF  IOxAPIC Bus:Device:Function   00F8h     R/W */
-    pThis->dev.config[0x70] = 0x80;
-    pThis->dev.config[0x76] = 0x0c;
-    pThis->dev.config[0x77] = 0x0c;
-    pThis->dev.config[0x78] = 0x02;
-    pThis->dev.config[0x79] = 0x00;
+    pThis->dev.abConfig[0x70] = 0x80;
+    pThis->dev.abConfig[0x76] = 0x0c;
+    pThis->dev.abConfig[0x77] = 0x0c;
+    pThis->dev.abConfig[0x78] = 0x02;
+    pThis->dev.abConfig[0x79] = 0x00;
     /* 80h        LPC_I/O_DEC I/O Decode Ranges           0000h     R/W */
     /* 82h-83h    LPC_EN   LPC I/F Enables                0000h     R/W */
     /* 84h-87h    GEN1_DEC   LPC I/F Generic Decode Range 1 00000000h   R/W */
@@ -287,18 +287,18 @@ static DECLCALLBACK(int) lpcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
     /* 90h-93h    GEN4_DEC LPC I/F Generic Decode Range 4 00000000h R/W */
 
     /* A0h-CFh    Power Management */
-    pThis->dev.config[0xa0] = 0x08;
-    pThis->dev.config[0xa2] = 0x00;
-    pThis->dev.config[0xa3] = 0x00;
-    pThis->dev.config[0xa4] = 0x00;
-    pThis->dev.config[0xa5] = 0x00;
-    pThis->dev.config[0xa6] = 0x00;
-    pThis->dev.config[0xa7] = 0x00;
-    pThis->dev.config[0xa8] = 0x0f;
-    pThis->dev.config[0xaa] = 0x00;
-    pThis->dev.config[0xab] = 0x00;
-    pThis->dev.config[0xac] = 0x00;
-    pThis->dev.config[0xae] = 0x00;
+    pThis->dev.abConfig[0xa0] = 0x08;
+    pThis->dev.abConfig[0xa2] = 0x00;
+    pThis->dev.abConfig[0xa3] = 0x00;
+    pThis->dev.abConfig[0xa4] = 0x00;
+    pThis->dev.abConfig[0xa5] = 0x00;
+    pThis->dev.abConfig[0xa6] = 0x00;
+    pThis->dev.abConfig[0xa7] = 0x00;
+    pThis->dev.abConfig[0xa8] = 0x0f;
+    pThis->dev.abConfig[0xaa] = 0x00;
+    pThis->dev.abConfig[0xab] = 0x00;
+    pThis->dev.abConfig[0xac] = 0x00;
+    pThis->dev.abConfig[0xae] = 0x00;
 
     /* D0h-D3h   FWH_SEL1  Firmware Hub Select 1  */
     /* D4h-D5h   FWH_SEL2  Firmware Hub Select 2 */
@@ -310,12 +310,13 @@ static DECLCALLBACK(int) lpcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
     /* E4h-EBh   FDVCT     Feature Vector Description */
 
     /* F0h-F3h RCBA Root Complex Base Address */
-    pThis->dev.config[0xf0] = RT_BYTE1(RCBA_BASE | 1); /* enabled */
-    pThis->dev.config[0xf1] = RT_BYTE2(RCBA_BASE);
-    pThis->dev.config[0xf2] = RT_BYTE3(RCBA_BASE);
-    pThis->dev.config[0xf3] = RT_BYTE4(RCBA_BASE);
+    pThis->dev.abConfig[0xf0] = RT_BYTE1(RCBA_BASE | 1); /* enabled */
+    pThis->dev.abConfig[0xf1] = RT_BYTE2(RCBA_BASE);
+    pThis->dev.abConfig[0xf2] = RT_BYTE3(RCBA_BASE);
+    pThis->dev.abConfig[0xf3] = RT_BYTE4(RCBA_BASE);
 
-    rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
+    rc = PDMDevHlpPCIRegisterEx(pDevIns, &pThis->dev, PDMPCIDEVREG_CFG_PRIMARY, PDMPCIDEVREG_F_NOT_MANDATORY_NO,
+                                31 /*uPciDevNo*/, 0 /*uPciFunNo*/, "lpc");
     if (RT_FAILURE(rc))
         return rc;
 
diff --git a/src/VBox/Devices/Samples/DevPlayground.cpp b/src/VBox/Devices/Samples/DevPlayground.cpp
index d60d178..dc16499 100644
--- a/src/VBox/Devices/Samples/DevPlayground.cpp
+++ b/src/VBox/Devices/Samples/DevPlayground.cpp
@@ -40,13 +40,29 @@
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
 /**
- * Device Instance Data.
+ * Playground device per function (sub-device) data.
+ */
+typedef struct VBOXPLAYGROUNDDEVICEFUNCTION
+{
+    /** The PCI devices. */
+    PDMPCIDEV   PciDev;
+    /** The function number. */
+    uint8_t     iFun;
+    /** Device function name. */
+    char        szName[31];
+} VBOXPLAYGROUNDDEVICEFUNCTION;
+/** Pointer to a PCI function of the playground device. */
+typedef VBOXPLAYGROUNDDEVICEFUNCTION *PVBOXPLAYGROUNDDEVICEFUNCTION;
+
+/**
+ * Playground device instance data.
  */
 typedef struct VBOXPLAYGROUNDDEVICE
 {
-    /** The PCI device. */
-    PCIDEVICE           PciDev;
+    /** PCI device functions. */
+    VBOXPLAYGROUNDDEVICEFUNCTION aPciFuns[8];
 } VBOXPLAYGROUNDDEVICE;
+/** Pointer to the instance data of a playground device instance. */
 typedef VBOXPLAYGROUNDDEVICE *PVBOXPLAYGROUNDDEVICE;
 
 
@@ -93,30 +109,24 @@ PDMBOTHCBDECL(int) devPlaygroundMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGC
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) devPlaygroundMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) devPlaygroundMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                          RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
-    NOREF(enmType);
-    int rc;
+    RT_NOREF(pPciDev, enmType, cb);
 
     switch (iRegion)
     {
         case 0:
-            rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL,
-                                       IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
-                                       devPlaygroundMMIOWrite, devPlaygroundMMIORead, "PG-BAR0");
-            break;
         case 2:
-            rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL,
-                                       IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
-                                       devPlaygroundMMIOWrite, devPlaygroundMMIORead, "PG-BAR2");
-            break;
+            Assert(enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64));
+            if (GCPhysAddress == NIL_RTGCPHYS)
+                return VINF_SUCCESS; /* We ignore the unmap notification. */
+            return PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
+
         default:
             /* We should never get here */
-            AssertMsgFailed(("Invalid PCI region param in map callback"));
-            rc = VERR_INTERNAL_ERROR;
+            AssertMsgFailedReturn(("Invalid PCI region param in map callback"), VERR_INTERNAL_ERROR);
     }
-    return rc;
-
 }
 
 
@@ -137,10 +147,6 @@ static DECLCALLBACK(int) devPlaygroundConstruct(PPDMDEVINS pDevIns, int iInstanc
      * Initialize the instance data so that the destructor won't mess up.
      */
     PVBOXPLAYGROUNDDEVICE pThis = PDMINS_2_DATA(pDevIns, PVBOXPLAYGROUNDDEVICE);
-    PCIDevSetVendorId(&pThis->PciDev, 0x80ee);
-    PCIDevSetDeviceId(&pThis->PciDev, 0xde4e);
-    PCIDevSetClassBase(&pThis->PciDev, 0x07);   /* communications device */
-    PCIDevSetClassSub(&pThis->PciDev, 0x80);    /* other communications device */
 
     /*
      * Validate and read the configuration.
@@ -153,19 +159,50 @@ static DECLCALLBACK(int) devPlaygroundConstruct(PPDMDEVINS pDevIns, int iInstanc
     /*
      * PCI device setup.
      */
-    int rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
-    if (RT_FAILURE(rc))
-        return rc;
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8*_1G64,
-                                      (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64),
-                                      devPlaygroundMap);
-    if (RT_FAILURE(rc))
-        return rc;
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8*_1G64,
-                                      (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64),
-                                      devPlaygroundMap);
-    if (RT_FAILURE(rc))
-        return rc;
+    uint32_t iPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
+    for (uint32_t iPciFun = 0; iPciFun < RT_ELEMENTS(pThis->aPciFuns); iPciFun++)
+    {
+        PVBOXPLAYGROUNDDEVICEFUNCTION pFun = &pThis->aPciFuns[iPciFun];
+        RTStrPrintf(pFun->szName, sizeof(pThis->aPciFuns[iPciFun].PciDev), "playground%u", iPciFun);
+        pFun->iFun = iPciFun;
+
+        PCIDevSetVendorId( &pFun->PciDev, 0x80ee);
+        PCIDevSetDeviceId( &pFun->PciDev, 0xde4e);
+        PCIDevSetClassBase(&pFun->PciDev, 0x07);   /* communications device */
+        PCIDevSetClassSub( &pFun->PciDev, 0x80);   /* other communications device */
+        int rc = PDMDevHlpPCIRegisterEx(pDevIns, &pFun->PciDev, iPciFun, 0 /*fFlags*/, iPciDevNo, iPciFun,
+                                        pThis->aPciFuns[iPciFun].szName);
+        AssertLogRelRCReturn(rc, rc);
+
+        /* First region. */
+        RTGCPHYS const cbFirst = iPciFun == 0 ? 8*_1G64 : iPciFun * _4K;
+        rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 0, cbFirst,
+                                            (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64),
+                                            devPlaygroundMap);
+        AssertLogRelRCReturn(rc, rc);
+        rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 0, cbFirst,
+                                        IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, "PG-BAR0",
+                                        NULL /*pvUser*/,  devPlaygroundMMIOWrite, devPlaygroundMMIORead, NULL /*pfnFill*/,
+                                        NIL_RTR0PTR /*pvUserR0*/, NULL /*pszWriteR0*/, NULL /*pszReadR0*/, NULL /*pszFillR0*/,
+                                        NIL_RTRCPTR /*pvUserRC*/, NULL /*pszWriteRC*/, NULL /*pszReadRC*/, NULL /*pszFillRC*/);
+        AssertLogRelRCReturn(rc, rc);
+
+        /* Second region. */
+        RTGCPHYS const cbSecond = iPciFun == 0  ? 256*_1G64 : iPciFun * _32K;
+        rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 2, cbSecond,
+                                            (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64),
+                                            devPlaygroundMap);
+        AssertLogRelRCReturn(rc, rc);
+        rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 2, cbSecond,
+                                        IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, "PG-BAR2",
+                                        NULL /*pvUser*/,  devPlaygroundMMIOWrite, devPlaygroundMMIORead, NULL /*pfnFill*/,
+                                        NIL_RTR0PTR /*pvUserR0*/, NULL /*pszWriteR0*/, NULL /*pszReadR0*/, NULL /*pszFillR0*/,
+                                        NIL_RTRCPTR /*pvUserRC*/, NULL /*pszWriteRC*/, NULL /*pszReadRC*/, NULL /*pszFillRC*/);
+        AssertLogRelRCReturn(rc, rc);
+
+        /* Subsequent function should use the same major as the previous one. */
+        iPciDevNo = PDMPCIDEVREG_DEV_NO_SAME_AS_PREV;
+    }
 
     return VINF_SUCCESS;
 }
diff --git a/src/VBox/Devices/Serial/DevSerial.cpp b/src/VBox/Devices/Serial/DevSerial.cpp
index 5ddb1b1..77b2c2b 100644
--- a/src/VBox/Devices/Serial/DevSerial.cpp
+++ b/src/VBox/Devices/Serial/DevSerial.cpp
@@ -229,7 +229,7 @@ typedef struct SerialState
     uint64_t                        char_transmit_time;
 
 #ifdef VBOX_SERIAL_PCI
-    PCIDEVICE                       PciDev;
+    PDMPCIDEV                       PciDev;
 #endif /* VBOX_SERIAL_PCI */
 } DEVSERIAL;
 /** Pointer to the serial device state. */
@@ -1050,8 +1050,8 @@ static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress,
-                                               RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) serialIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                               RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     PDEVSERIAL pThis = RT_FROM_MEMBER(pPciDev, DEVSERIAL, PciDev);
     int rc = VINF_SUCCESS;
@@ -1067,7 +1067,7 @@ static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, int iRegion,
     /*
      * Register our port IO handlers.
      */
-    rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
+    rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
                                  serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
     AssertRC(rc);
     return rc;
@@ -1188,17 +1188,17 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
 
 #ifdef VBOX_SERIAL_PCI
     /* the PCI device */
-    pThis->PciDev.config[0x00] = 0xee; /* Vendor: ??? */
-    pThis->PciDev.config[0x01] = 0x80;
-    pThis->PciDev.config[0x02] = 0x01; /* Device: ??? */
-    pThis->PciDev.config[0x03] = 0x01;
-    pThis->PciDev.config[0x04] = PCI_COMMAND_IOACCESS;
-    pThis->PciDev.config[0x09] = 0x01; /* Programming interface: 16450 */
-    pThis->PciDev.config[0x0a] = 0x00; /* Subclass: Serial controller */
-    pThis->PciDev.config[0x0b] = 0x07; /* Class: Communication controller */
-    pThis->PciDev.config[0x0e] = 0x00; /* Header type: standard */
-    pThis->PciDev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
-    pThis->PciDev.config[0x3d] = 1;    /* interrupt pin 0 */
+    pThis->PciDev.abConfig[0x00] = 0xee; /* Vendor: ??? */
+    pThis->PciDev.abConfig[0x01] = 0x80;
+    pThis->PciDev.abConfig[0x02] = 0x01; /* Device: ??? */
+    pThis->PciDev.abConfig[0x03] = 0x01;
+    pThis->PciDev.abConfig[0x04] = PCI_COMMAND_IOACCESS;
+    pThis->PciDev.abConfig[0x09] = 0x01; /* Programming interface: 16450 */
+    pThis->PciDev.abConfig[0x0a] = 0x00; /* Subclass: Serial controller */
+    pThis->PciDev.abConfig[0x0b] = 0x07; /* Class: Communication controller */
+    pThis->PciDev.abConfig[0x0e] = 0x00; /* Header type: standard */
+    pThis->PciDev.abConfig[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
+    pThis->PciDev.abConfig[0x3d] = 1;    /* interrupt pin 0 */
 #endif /* VBOX_SERIAL_PCI */
 
     /*
diff --git a/src/VBox/Devices/Storage/DevAHCI.cpp b/src/VBox/Devices/Storage/DevAHCI.cpp
index 51d222a..98e8ee6 100644
--- a/src/VBox/Devices/Storage/DevAHCI.cpp
+++ b/src/VBox/Devices/Storage/DevAHCI.cpp
@@ -596,7 +596,7 @@ AssertCompileSizeAlignment(AHCIPort, 8);
 typedef struct AHCI
 {
     /** The PCI device structure. */
-    PCIDEVICE                       dev;
+    PDMPCIDEV                       dev;
     /** Pointer to the device instance - R3 ptr */
     PPDMDEVINSR3                    pDevInsR3;
     /** Pointer to the device instance - R0 ptr */
@@ -2551,12 +2551,11 @@ PDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Po
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
-                                       RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ahciR3MMIOMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                       RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, enmType);
     PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
-    PPDMDEVINS pDevIns = pPciDev->pDevIns;
 
     Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
 
@@ -2596,12 +2595,11 @@ static DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iReg
  *      Map the legacy I/O port ranges to make Solaris work with the
  *      controller.}
  */
-static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
-                                                    RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                                    RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, enmType);
     PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
-    PPDMDEVINS pDevIns = pPciDev->pDevIns;
     int   rc = VINF_SUCCESS;
 
     Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
@@ -2637,12 +2635,11 @@ static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsign
  * @callback_method_impl{FNPCIIOREGIONMAP,
  *      Map the BMDMA I/O port range (used for the Index/Data pair register access)}
  */
-static DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
-                                                 RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                                 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, enmType);
     PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
-    PPDMDEVINS pDevIns = pPciDev->pDevIns;
     int   rc = VINF_SUCCESS;
 
     Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
@@ -8415,18 +8412,18 @@ static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
     PCIDevSetInterruptLine(&pThis->dev, 0x00);
     PCIDevSetInterruptPin (&pThis->dev, 0x01);
 
-    pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
-    pThis->dev.config[0x71] = 0xa8; /* next */
-    pThis->dev.config[0x72] = 0x03; /* version ? */
+    pThis->dev.abConfig[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
+    pThis->dev.abConfig[0x71] = 0xa8; /* next */
+    pThis->dev.abConfig[0x72] = 0x03; /* version ? */
 
-    pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
-    pThis->dev.config[0x92] = 0x3f;
-    pThis->dev.config[0x94] = 0x80;
-    pThis->dev.config[0x95] = 0x01;
-    pThis->dev.config[0x97] = 0x78;
+    pThis->dev.abConfig[0x90] = 0x40; /* AHCI mode. */
+    pThis->dev.abConfig[0x92] = 0x3f;
+    pThis->dev.abConfig[0x94] = 0x80;
+    pThis->dev.abConfig[0x95] = 0x01;
+    pThis->dev.abConfig[0x97] = 0x78;
 
-    pThis->dev.config[0xa8] = 0x12;                /* SATACR capability */
-    pThis->dev.config[0xa9] = 0x00;                /* next */
+    pThis->dev.abConfig[0xa8] = 0x12;              /* SATACR capability */
+    pThis->dev.abConfig[0xa9] = 0x00;              /* next */
     PCIDevSetWord(&pThis->dev, 0xaa, 0x0010);      /* Revision */
     PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
 
@@ -8616,7 +8613,7 @@ static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
 
             /* Mark that a device is present on that port */
             if (i < 6)
-                pThis->dev.config[0x93] |= (1 << i);
+                pThis->dev.abConfig[0x93] |= (1 << i);
 
             /*
              * Init vendor product data.
diff --git a/src/VBox/Devices/Storage/DevATA.cpp b/src/VBox/Devices/Storage/DevATA.cpp
index 8bcf880..4dea902 100644
--- a/src/VBox/Devices/Storage/DevATA.cpp
+++ b/src/VBox/Devices/Storage/DevATA.cpp
@@ -481,12 +481,12 @@ typedef enum CHIPSET
 /**
  * The state of the ATA PCI device.
  *
- * @extends     PCIDEVICE
+ * @extends     PDMPCIDEV
  * @implements  PDMILEDPORTS
  */
 typedef struct PCIATAState
 {
-    PCIDEVICE           dev;
+    PDMPCIDEV           dev;
     /** The controllers. */
     ATACONTROLLER       aCts[2];
     /** Pointer to device instance. */
@@ -6111,17 +6111,9 @@ PDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPOR
 #ifdef IN_RING3
 
 /**
- * Callback function for mapping an PCI I/O region.
- *
- * @return VBox status code.
- * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
- * @param   iRegion         The region number.
- * @param   GCPhysAddress   Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
- *                          I/O port, else it's a physical address.
- *                          This address is *NOT* relative to pci_mem_base like earlier!
- * @param   enmType         One of the PCI_ADDRESS_SPACE_* values.
+ * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) ataR3BMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
+static DECLCALLBACK(int) ataR3BMDMAIORangeMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
                                               RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, cb, enmType);
@@ -6134,7 +6126,7 @@ static DECLCALLBACK(int) ataR3BMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ i
     /* Register the port range. */
     for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
     {
-        int rc2 = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
+        int rc2 = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
                                           (RTHCPTR)(uintptr_t)i, ataBMDMAIOPortWrite, ataBMDMAIOPortRead,
                                           NULL, NULL, "ATA Bus Master DMA");
         AssertRC(rc2);
@@ -6143,7 +6135,7 @@ static DECLCALLBACK(int) ataR3BMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ i
 
         if (pThis->fRCEnabled)
         {
-            rc2 = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
+            rc2 = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
                                             (RTGCPTR)i, "ataBMDMAIOPortWrite", "ataBMDMAIOPortRead",
                                             NULL, NULL, "ATA Bus Master DMA");
             AssertRC(rc2);
@@ -6152,7 +6144,7 @@ static DECLCALLBACK(int) ataR3BMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ i
         }
         if (pThis->fR0Enabled)
         {
-            rc2 = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
+            rc2 = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
                                             (RTR0PTR)i, "ataBMDMAIOPortWrite", "ataBMDMAIOPortRead",
                                             NULL, NULL, "ATA Bus Master DMA");
             AssertRC(rc2);
@@ -7425,9 +7417,9 @@ static DECLCALLBACK(int) ataR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM
         case CHIPSET_ICH6:
             PCIDevSetDeviceId(&pThis->dev, 0x269e); /* ICH6 IDE */
             /** @todo do we need it? Do we need anything else? */
-            pThis->dev.config[0x48] = 0x00; /* UDMACTL */
-            pThis->dev.config[0x4A] = 0x00; /* UDMATIM */
-            pThis->dev.config[0x4B] = 0x00;
+            pThis->dev.abConfig[0x48] = 0x00; /* UDMACTL */
+            pThis->dev.abConfig[0x4A] = 0x00; /* UDMATIM */
+            pThis->dev.abConfig[0x4B] = 0x00;
             {
                 /*
                  * See www.intel.com/Assets/PDF/manual/298600.pdf p. 30
@@ -7437,16 +7429,16 @@ static DECLCALLBACK(int) ataR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM
                  *   SCR0, SCR1: 80-pin secondary cable reporting for both disks
                  */
                 uint16_t u16Config = (1<<10) | (1<<7)  | (1<<6) | (1<<5) | (1<<4) ;
-                pThis->dev.config[0x54] = u16Config & 0xff;
-                pThis->dev.config[0x55] = u16Config >> 8;
+                pThis->dev.abConfig[0x54] = u16Config & 0xff;
+                pThis->dev.abConfig[0x55] = u16Config >> 8;
             }
             break;
         case CHIPSET_PIIX4:
             PCIDevSetDeviceId(&pThis->dev, 0x7111); /* PIIX4 IDE */
             PCIDevSetRevisionId(&pThis->dev, 0x01); /* PIIX4E */
-            pThis->dev.config[0x48] = 0x00; /* UDMACTL */
-            pThis->dev.config[0x4A] = 0x00; /* UDMATIM */
-            pThis->dev.config[0x4B] = 0x00;
+            pThis->dev.abConfig[0x48] = 0x00; /* UDMACTL */
+            pThis->dev.abConfig[0x4A] = 0x00; /* UDMATIM */
+            pThis->dev.abConfig[0x4B] = 0x00;
             break;
         case CHIPSET_PIIX3:
             PCIDevSetDeviceId(&pThis->dev, 0x7010); /* PIIX3 IDE */
@@ -7505,18 +7497,14 @@ static DECLCALLBACK(int) ataR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM
 
     /*
      * Register the PCI device.
-     * N.B. There's a hack in the PIIX3 PCI bridge device to assign this
-     *      device the slot next to itself.
      */
-    rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
+    rc = PDMDevHlpPCIRegisterEx(pDevIns, &pThis->dev, PDMPCIDEVREG_CFG_PRIMARY, PDMPCIDEVREG_F_NOT_MANDATORY_NO,
+                                1 /*uPciDevNo*/, 1 /*uPciDevFn*/, "piix3ide");
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pDevIns, rc,
-                                N_("PIIX3 cannot register PCI device"));
-    //AssertMsg(pThis->dev.devfn == 9 || iInstance != 0, ("pThis->dev.devfn=%d\n", pThis->dev.devfn));
+        return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register PCI device"));
     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ataR3BMDMAIORangeMap);
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pDevIns, rc,
-                                N_("PIIX3 cannot register PCI I/O region for BMDMA"));
+        return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register PCI I/O region for BMDMA"));
 
     /*
      * Register the I/O ports.
diff --git a/src/VBox/Devices/Storage/DevBusLogic.cpp b/src/VBox/Devices/Storage/DevBusLogic.cpp
index 93dd37d..2856f63 100644
--- a/src/VBox/Devices/Storage/DevBusLogic.cpp
+++ b/src/VBox/Devices/Storage/DevBusLogic.cpp
@@ -317,13 +317,13 @@ typedef struct BUSLOGICTASKSTATE *PBUSLOGICTASKSTATE;
 /**
  * Main BusLogic device state.
  *
- * @extends     PCIDEVICE
+ * @extends     PDMPCIDEV
  * @implements  PDMILEDPORTS
  */
 typedef struct BUSLOGIC
 {
     /** The PCI device structure. */
-    PCIDEVICE                       dev;
+    PDMPCIDEV                       dev;
     /** Pointer to the device instance - HC ptr */
     PPDMDEVINSR3                    pDevInsR3;
     /** Pointer to the device instance - R0 ptr */
@@ -2770,11 +2770,10 @@ static void buslogicR3RedoSetWarning(PBUSLOGIC pThis, int rc)
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) buslogicR3MmioMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
+static DECLCALLBACK(int) buslogicR3MmioMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
                                            RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
-    RT_NOREF(iRegion);
-    PPDMDEVINS pDevIns = pPciDev->pDevIns;
+    RT_NOREF(pPciDev, iRegion);
     PBUSLOGIC  pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
     int   rc = VINF_SUCCESS;
 
diff --git a/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp b/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
index 9d115b6..061c016 100644
--- a/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
+++ b/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
@@ -174,7 +174,7 @@ typedef struct LSILOGICREQ *PLSILOGICREQ;
 typedef struct LSILOGICSCSI
 {
     /** PCI device structure. */
-    PCIDEVICE            PciDev;
+    PDMPCIDEV            PciDev;
     /** Pointer to the device instance. - R3 ptr. */
     PPDMDEVINSR3         pDevInsR3;
     /** Pointer to the device instance. - R0 ptr. */
@@ -3639,7 +3639,7 @@ static void lsilogicR3InitializeConfigurationPages(PLSILOGICSCSI pThis)
     pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEnabled = true;
     pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEmbedded = true;
     pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIBusNumber = 0;
-    pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn     = pThis->PciDev.devfn;
+    pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn     = pThis->PciDev.uDevFn;
 
     /* I/O Unit page 3. */
     MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3,
@@ -3938,13 +3938,13 @@ static DECLCALLBACK(int) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pv
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) lsilogicR3Map(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
+static DECLCALLBACK(int) lsilogicR3Map(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
                                        RTGCPHYS GCPhysAddress, RTGCPHYS cb,
                                        PCIADDRESSSPACE enmType)
 {
-    PPDMDEVINS pDevIns = pPciDev->pDevIns;
-    PLSILOGICSCSI  pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
-    int   rc = VINF_SUCCESS;
+    RT_NOREF(pPciDev);
+    PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
+    int         rc = VINF_SUCCESS;
     const char *pcszCtrl = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
                            ? "LsiLogic"
                            : "LsiLogicSas";
diff --git a/src/VBox/Devices/USB/DevOHCI.cpp b/src/VBox/Devices/USB/DevOHCI.cpp
index f7e7a42..d437987 100644
--- a/src/VBox/Devices/USB/DevOHCI.cpp
+++ b/src/VBox/Devices/USB/DevOHCI.cpp
@@ -263,7 +263,7 @@ typedef struct OHCIPAGECACHE
 typedef struct OHCI
 {
     /** The PCI device. */
-    PCIDEVICE           PciDev;
+    PDMPCIDEV           PciDev;
 
     /** Pointer to the device instance - R3 ptr. */
     PPDMDEVINSR3        pDevInsR3;
@@ -4149,7 +4149,7 @@ static void ohciBusStart(POHCI pThis)
     VUSBIDevPowerOn(pThis->RootHub.pIDev);
     pThis->dqic = 0x7;
 
-    Log(("ohci: %s: Bus started\n", pThis->PciDev.name));
+    Log(("ohci: %s: Bus started\n", pThis->PciDev.pszNameR3));
 
     pThis->SofTime = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns));
     int rc = pThis->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThis->RootHub.pIRhConn, OHCI_DEFAULT_TIMER_FREQ);
@@ -4888,7 +4888,7 @@ static int HcRhDescriptorA_w(POHCI pThis, uint32_t iReg, uint32_t val)
     if ((val & (OHCI_RHA_NDP | OHCI_RHA_DT)) != OHCI_NDP_CFG(pThis))
     {
         Log(("ohci: %s: invalid write to NDP or DT in roothub descriptor A!!! val=0x%.8x\n",
-                pThis->PciDev.name, val));
+             pThis->PciDev.pszNameR3, val));
         val &= ~(OHCI_RHA_NDP | OHCI_RHA_DT);
         val |= OHCI_NDP_CFG(pThis);
     }
@@ -4924,8 +4924,7 @@ static int HcRhDescriptorB_w(POHCI pThis, uint32_t iReg, uint32_t val)
 
     if ( pThis->RootHub.desc_b != val )
         Log(("ohci: %s: unsupported write to root descriptor B!!! 0x%.8x -> 0x%.8x\n",
-                pThis->PciDev.name,
-                pThis->RootHub.desc_b, val));
+             pThis->PciDev.pszNameR3, pThis->RootHub.desc_b, val));
     pThis->RootHub.desc_b = val;
     return VINF_SUCCESS;
 }
@@ -4969,7 +4968,7 @@ static int HcRhStatus_w(POHCI pThis, uint32_t iReg, uint32_t val)
     if ( val & OHCI_RHS_LPSC )
     {
         unsigned i;
-        Log2(("ohci: %s: global power up\n", pThis->PciDev.name));
+        Log2(("ohci: %s: global power up\n", pThis->PciDev.pszNameR3));
         for (i = 0; i < OHCI_NDP_CFG(pThis); i++)
             rhport_power(&pThis->RootHub, i, true /* power up */);
     }
@@ -4978,7 +4977,7 @@ static int HcRhStatus_w(POHCI pThis, uint32_t iReg, uint32_t val)
     if ( val & OHCI_RHS_LPS )
     {
         unsigned i;
-        Log2(("ohci: %s: global power down\n", pThis->PciDev.name));
+        Log2(("ohci: %s: global power down\n", pThis->PciDev.pszNameR3));
         for (i = 0; i < OHCI_NDP_CFG(pThis); i++)
             rhport_power(&pThis->RootHub, i, false /* power down */);
     }
@@ -5359,11 +5358,12 @@ PDMBOTHCBDECL(int) ohciMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPh
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP}
  */
-static DECLCALLBACK(int) ohciR3Map(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ohciR3Map(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                   RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF(iRegion, enmType);
     POHCI pThis = (POHCI)pPciDev;
-    int rc = PDMDevHlpMMIORegister(pThis->CTX_SUFF(pDevIns), GCPhysAddress, cb, NULL /*pvUser*/,
+    int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
                                    IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED
                                    | IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE,
                                    ohciMmioWrite, ohciMmioRead, "USB OHCI");
@@ -5372,13 +5372,11 @@ static DECLCALLBACK(int) ohciR3Map(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCP
 
     if (pThis->fRZEnabled)
     {
-        rc = PDMDevHlpMMIORegisterRC(pThis->CTX_SUFF(pDevIns), GCPhysAddress, cb,
-                                     NIL_RTRCPTR /*pvUser*/, "ohciMmioWrite", "ohciMmioRead");
+        rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ohciMmioWrite", "ohciMmioRead");
         if (RT_FAILURE(rc))
             return rc;
 
-        rc = PDMDevHlpMMIORegisterR0(pThis->CTX_SUFF(pDevIns), GCPhysAddress, cb,
-                                     NIL_RTR0PTR /*pvUser*/, "ohciMmioWrite", "ohciMmioRead");
+        rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ohciMmioWrite", "ohciMmioRead");
         if (RT_FAILURE(rc))
             return rc;
     }
@@ -5633,12 +5631,12 @@ static DECLCALLBACK(int) ohciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
     {
         static SSMFIELD const s_aOhciFields22[] =
         {
-            SSMFIELD_ENTRY_OLD(           PciDev.config,                256),   /* DevPCI restores this. */
+            SSMFIELD_ENTRY_OLD(           PciDev.abConfig,              256),   /* DevPCI restores this. */
             SSMFIELD_ENTRY_OLD(           PciDev.Int,                   224),
-            SSMFIELD_ENTRY_OLD(           PciDev.devfn,                 4),
+            SSMFIELD_ENTRY_OLD(           PciDev.uDevFn,                4),
             SSMFIELD_ENTRY_OLD(           PciDev.Alignment0,            4),
-            SSMFIELD_ENTRY_OLD_HCPTR(     PciDev.name),
-            SSMFIELD_ENTRY_OLD_HCPTR(     PciDev.pDevIns),
+            SSMFIELD_ENTRY_OLD_HCPTR(     PciDev.pszNameR3),
+            SSMFIELD_ENTRY_OLD_HCPTR(     PciDev.pvReserved),
             SSMFIELD_ENTRY_OLD_HCPTR(     pDevInsR3),
             SSMFIELD_ENTRY_OLD_HCPTR(     pEndOfFrameTimerR3),
             SSMFIELD_ENTRY_OLD_HCPTR(     pDevInsR0),
diff --git a/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp b/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
index cefa376..65384c2 100644
--- a/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
+++ b/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
@@ -110,8 +110,16 @@ static inline bool rtcsTrue() { return true; }
  */
 typedef struct USBPROXYURBLNX
 {
-    /** The kernel URB data */
+    /** The kernel URB data. */
+#if RT_GNUC_PREREQ(6, 0)
+    /* gcc 6.2 complains about the [] member of KUrb */
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wpedantic"
+#endif
     struct usbdevfs_urb             KUrb;
+#if RT_GNUC_PREREQ(6, 0)
+# pragma GCC diagnostic pop
+#endif
     /** Space filler for the isochronous packets. */
     struct usbdevfs_iso_packet_desc aIsocPktsDonUseTheseUseTheOnesInKUrb[8];
     /** Node to link the URB in of the existing lists. */
@@ -121,11 +129,11 @@ typedef struct USBPROXYURBLNX
     /** The next linux URB if split up. */
     struct USBPROXYURBLNX           *pSplitNext;
     /** Don't report these back. */
-    bool                             fCanceledBySubmit;
+    bool                            fCanceledBySubmit;
     /** This split element is reaped. */
-    bool                             fSplitElementReaped;
+    bool                            fSplitElementReaped;
     /** Size to transfer in remaining fragments of a split URB */
-    uint32_t                         cbSplitRemaining;
+    uint32_t                        cbSplitRemaining;
 } USBPROXYURBLNX, *PUSBPROXYURBLNX;
 
 /**
diff --git a/src/VBox/Devices/VMMDev/VMMDev.cpp b/src/VBox/Devices/VMMDev/VMMDev.cpp
index d039e8a..3060205 100644
--- a/src/VBox/Devices/VMMDev/VMMDev.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDev.cpp
@@ -2877,8 +2877,8 @@ static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser,
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP,MMIO/MMIO2 regions}
  */
-static DECLCALLBACK(int)
-vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                              RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF1(cb);
     LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%RGp enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
@@ -2896,7 +2896,7 @@ vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RT
              */
             pThis->GCPhysVMMDevRAM = GCPhysAddress;
             Assert(pThis->GCPhysVMMDevRAM == GCPhysAddress);
-            rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
+            rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
         }
         else
         {
@@ -2918,16 +2918,16 @@ vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RT
              */
             pThis->GCPhysVMMDevHeap = GCPhysAddress;
             Assert(pThis->GCPhysVMMDevHeap == GCPhysAddress);
-            rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
+            rc = PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
             if (RT_SUCCESS(rc))
-                rc = PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
+                rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
         }
         else
         {
             /*
              * It is about to be unmapped, just clean up.
              */
-            PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
+            PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
             pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
             rc = VINF_SUCCESS;
         }
@@ -2945,8 +2945,8 @@ vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RT
 /**
  * @callback_method_impl{FNPCIIOREGIONMAP,I/O Port Region}
  */
-static DECLCALLBACK(int)
-vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                               RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
 {
     RT_NOREF3(iRegion, cb, enmType);
     PVMMDEV pThis = RT_FROM_MEMBER(pPciDev, VMMDEV, PciDev);
@@ -2958,7 +2958,7 @@ vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, R
     /*
      * Register our port IO handlers.
      */
-    int rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
+    int rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
                                      pThis, vmmdevRequestHandler, NULL, NULL, NULL, "VMMDev Request Handler");
     AssertRC(rc);
     return rc;
@@ -4144,34 +4144,13 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
 #endif
 
     /*
-     * Allocate and initialize the MMIO2 memory.
-     */
-    rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevRAMR3, "VMMDev");
-    if (RT_FAILURE(rc))
-        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
-                                   N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
-    vmmdevInitRam(pThis);
-
-    if (pThis->fHeapEnabled)
-    {
-        rc = PDMDevHlpMMIO2Register(pDevIns, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
-        if (RT_FAILURE(rc))
-            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
-                                       N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
-
-        /* Register the memory area with PDM so HM can access it before it's mapped. */
-        rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
-        AssertLogRelRCReturn(rc, rc);
-    }
-
-    /*
      * Register the PCI device.
      */
     rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
     if (RT_FAILURE(rc))
         return rc;
-    if (pThis->PciDev.devfn != 32 || iInstance != 0)
-        Log(("!!WARNING!!: pThis->PciDev.devfn=%d (ignore if testcase or no started by Main)\n", pThis->PciDev.devfn));
+    if (pThis->PciDev.uDevFn != 32 || iInstance != 0)
+        Log(("!!WARNING!!: pThis->PciDev.uDevFn=%d (ignore if testcase or no started by Main)\n", pThis->PciDev.uDevFn));
     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
     if (RT_FAILURE(rc))
         return rc;
@@ -4185,6 +4164,29 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
             return rc;
     }
 
+    /*
+     * Allocate and initialize the MMIO2 memory.
+     */
+    rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/,
+                                (void **)&pThis->pVMMDevRAMR3, "VMMDev");
+    if (RT_FAILURE(rc))
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                   N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
+    vmmdevInitRam(pThis);
+
+    if (pThis->fHeapEnabled)
+    {
+        rc = PDMDevHlpMMIO2Register(pDevIns, &pThis->PciDev, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/,
+                                    (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
+        if (RT_FAILURE(rc))
+            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                       N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
+
+        /* Register the memory area with PDM so HM can access it before it's mapped. */
+        rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
+        AssertLogRelRCReturn(rc, rc);
+    }
+
 #ifndef VBOX_WITHOUT_TESTING_FEATURES
     /*
      * Initialize testing.
diff --git a/src/VBox/Devices/VMMDev/VMMDevState.h b/src/VBox/Devices/VMMDev/VMMDevState.h
index ab1bc91..e3bcd1a 100644
--- a/src/VBox/Devices/VMMDev/VMMDevState.h
+++ b/src/VBox/Devices/VMMDev/VMMDevState.h
@@ -114,7 +114,7 @@ typedef VMMDEVFACILITYSTATUSENTRY *PVMMDEVFACILITYSTATUSENTRY;
 typedef struct VMMDevState
 {
     /** The PCI device structure. */
-    PCIDevice           PciDev;
+    PDMPCIDEV           PciDev;
     /** The critical section for this device.
      * @remarks We use this rather than the default one, it's simpler with all
      *          the driver interfaces where we have to waste time digging out the
diff --git a/src/VBox/Devices/VirtIO/Virtio.cpp b/src/VBox/Devices/VirtIO/Virtio.cpp
index 63741f6..19a1705 100644
--- a/src/VBox/Devices/VirtIO/Virtio.cpp
+++ b/src/VBox/Devices/VirtIO/Virtio.cpp
@@ -618,31 +618,6 @@ void vpciSetReadLed(PVPCISTATE pState, bool fOn)
         pState->led.Actual.s.fReading = fOn;
 }
 
-/**
- * Sets 8-bit register in PCI configuration space.
- * @param   refPciDev   The PCI device.
- * @param   uOffset     The register offset.
- * @param   u16Value    The value to store in the register.
- * @thread  EMT
- */
-DECLINLINE(void) vpciCfgSetU8(PCIDEVICE& refPciDev, uint32_t uOffset, uint8_t u8Value)
-{
-    Assert(uOffset < sizeof(refPciDev.config));
-    refPciDev.config[uOffset] = u8Value;
-}
-
-/**
- * Sets 16-bit register in PCI configuration space.
- * @param   refPciDev   The PCI device.
- * @param   uOffset     The register offset.
- * @param   u16Value    The value to store in the register.
- * @thread  EMT
- */
-DECLINLINE(void) vpciCfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t u16Value)
-{
-    Assert(uOffset+sizeof(u16Value) <= sizeof(refPciDev.config));
-    *(uint16_t*)&refPciDev.config[uOffset] = u16Value;
-}
 
 #if 0 /* unused */
 /**
@@ -652,7 +627,7 @@ DECLINLINE(void) vpciCfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t
  * @param   u32Value    The value to store in the register.
  * @thread  EMT
  */
-DECLINLINE(void) vpciCfgSetU32(PCIDEVICE& refPciDev, uint32_t uOffset, uint32_t u32Value)
+DECLINLINE(void) vpciCfgSetU32(PDMPCIDEV& refPciDev, uint32_t uOffset, uint32_t u32Value)
 {
     Assert(uOffset+sizeof(u32Value) <= sizeof(refPciDev.config));
     *(uint32_t*)&refPciDev.config[uOffset] = u32Value;
@@ -799,27 +774,27 @@ int vpciLoadExec(PVPCISTATE pState, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t
  * @param   uClass       Class of PCI device (network, etc)
  * @thread  EMT
  */
-static DECLCALLBACK(void) vpciConfigure(PCIDEVICE& pci,
+static DECLCALLBACK(void) vpciConfigure(PDMPCIDEV& pci,
                                         uint16_t uDeviceId,
                                         uint16_t uClass)
 {
     /* Configure PCI Device, assume 32-bit mode ******************************/
     PCIDevSetVendorId(&pci, DEVICE_PCI_VENDOR_ID);
     PCIDevSetDeviceId(&pci, DEVICE_PCI_BASE_ID + uDeviceId);
-    vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, DEVICE_PCI_SUBSYSTEM_VENDOR_ID);
-    vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_ID, DEVICE_PCI_SUBSYSTEM_BASE_ID + uDeviceId);
+    PDMPciDevSetWord(&pci,  VBOX_PCI_SUBSYSTEM_VENDOR_ID, DEVICE_PCI_SUBSYSTEM_VENDOR_ID);
+    PDMPciDevSetWord(&pci,  VBOX_PCI_SUBSYSTEM_ID, DEVICE_PCI_SUBSYSTEM_BASE_ID + uDeviceId);
 
     /* ABI version, must be equal 0 as of 2.6.30 kernel. */
-    vpciCfgSetU8( pci, VBOX_PCI_REVISION_ID,          0x00);
+    PDMPciDevSetByte(&pci,  VBOX_PCI_REVISION_ID,          0x00);
     /* Ethernet adapter */
-    vpciCfgSetU8( pci, VBOX_PCI_CLASS_PROG,           0x00);
-    vpciCfgSetU16(pci, VBOX_PCI_CLASS_DEVICE,       uClass);
+    PDMPciDevSetByte(&pci,  VBOX_PCI_CLASS_PROG,           0x00);
+    PDMPciDevSetWord(&pci,  VBOX_PCI_CLASS_DEVICE,         uClass);
     /* Interrupt Pin: INTA# */
-    vpciCfgSetU8( pci, VBOX_PCI_INTERRUPT_PIN,        0x01);
+    PDMPciDevSetByte(&pci,  VBOX_PCI_INTERRUPT_PIN,        0x01);
 
 #ifdef VBOX_WITH_MSI_DEVICES
-    PCIDevSetCapabilityList     (&pci, 0x80);
-    PCIDevSetStatus             (&pci, VBOX_PCI_STATUS_CAP_LIST);
+    PCIDevSetCapabilityList(&pci, 0x80);
+    PCIDevSetStatus( &pci,  VBOX_PCI_STATUS_CAP_LIST);
 #endif
 }
 
diff --git a/src/VBox/Devices/VirtIO/Virtio.h b/src/VBox/Devices/VirtIO/Virtio.h
index c16ecd9..8533375 100644
--- a/src/VBox/Devices/VirtIO/Virtio.h
+++ b/src/VBox/Devices/VirtIO/Virtio.h
@@ -187,7 +187,7 @@ typedef struct VPCIState_st
 #endif
 
     /** TODO */
-    PCIDEVICE              pciDevice;
+    PDMPCIDEV              pciDevice;
     /** Base port of I/O space region. */
     RTIOPORT               IOPortBase;
 
diff --git a/src/VBox/Devices/build/VBoxDD.cpp b/src/VBox/Devices/build/VBoxDD.cpp
index 728a6f6..24b7e94 100644
--- a/src/VBox/Devices/build/VBoxDD.cpp
+++ b/src/VBox/Devices/build/VBoxDD.cpp
@@ -126,7 +126,11 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSB16);
     if (RT_FAILURE(rc))
         return rc;
+#ifdef VBOX_WITH_AUDIO_50
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceICH6_HDA);
+#else
+    rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceHDA);
+#endif
     if (RT_FAILURE(rc))
         return rc;
 #ifdef VBOX_WITH_VUSB
diff --git a/src/VBox/Devices/build/VBoxDD.h b/src/VBox/Devices/build/VBoxDD.h
index 85be782..bb9560a 100644
--- a/src/VBox/Devices/build/VBoxDD.h
+++ b/src/VBox/Devices/build/VBoxDD.h
@@ -57,7 +57,11 @@ extern const PDMDEVREG g_DeviceINIP;
 #endif
 extern const PDMDEVREG g_DeviceICHAC97;
 extern const PDMDEVREG g_DeviceSB16;
+#ifdef VBOX_WITH_AUDIO_50
 extern const PDMDEVREG g_DeviceICH6_HDA;
+#else
+extern const PDMDEVREG g_DeviceHDA;
+#endif
 extern const PDMDEVREG g_DeviceOHCI;
 extern const PDMDEVREG g_DeviceEHCI;
 extern const PDMDEVREG g_DeviceXHCI;
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
index 8fbd39e..5c133d7 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
@@ -122,7 +122,7 @@
 # undef LOG_GROUP
 # include "../Audio/DevIchAc97.cpp"
 # undef LOG_GROUP
-# include "../Audio/DevIchHda.cpp"
+# include "../Audio/DevHDA.cpp"
 
 #include <stdio.h>
 
@@ -280,8 +280,8 @@ int main()
 
     /* Basic alignment checks. */
     CHECK_MEMBER_ALIGNMENT(PDMDEVINS, achInstanceData, 64);
-    CHECK_MEMBER_ALIGNMENT(PCIDEVICE, Int.s, 16);
-    CHECK_MEMBER_ALIGNMENT(PCIDEVICE, Int.s.aIORegions, 16);
+    CHECK_MEMBER_ALIGNMENT(PDMPCIDEV, Int.s, 16);
+    CHECK_MEMBER_ALIGNMENT(PDMPCIDEV, Int.s.aIORegions, 16);
 
     /*
      * Misc alignment checks (keep this somewhat alphabetical).
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index 80ff057..3531b1f 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -116,7 +116,7 @@
 # undef LOG_GROUP
 # include "../Audio/DevIchAc97.cpp"
 # undef LOG_GROUP
-# include "../Audio/DevIchHda.cpp"
+# include "../Audio/DevHDA.cpp"
 #ifdef VBOX_WITH_NVME_IMPL
 # undef LOG_GROUP
 # include "../Storage/DevNVMe.cpp"
@@ -147,31 +147,31 @@ int main()
     GEN_CHECK_OFF(PDMDEVINS, achInstanceData);
 
     /* DevPCI.cpp */
-    GEN_CHECK_SIZE(PCIDEVICE);
-    GEN_CHECK_SIZE(PCIDEVICEINT);
+    GEN_CHECK_SIZE(PDMPCIDEV);
+    GEN_CHECK_SIZE(PDMPCIDEVINT);
     GEN_CHECK_SIZE(PCIIOREGION);
-    GEN_CHECK_OFF(PCIDEVICE, config);
-    GEN_CHECK_OFF(PCIDEVICE, devfn);
-    GEN_CHECK_OFF(PCIDEVICE, name);
-    GEN_CHECK_OFF(PCIDEVICE, pDevIns);
-    GEN_CHECK_OFF(PCIDEVICE, Int);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions[1]);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions[PCI_NUM_REGIONS - 1]);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions[0].addr);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions[0].size);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions[0].type);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.aIORegions[0].padding);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pBusR3);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pBusR0);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pBusRC);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pfnConfigRead);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pfnConfigWrite);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.fFlags);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.uIrqPinState);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pfnBridgeConfigRead);
-    GEN_CHECK_OFF(PCIDEVICE, Int.s.pfnBridgeConfigWrite);
-    GEN_CHECK_PADDING(PCIDEVICE, Int, 8);
+    GEN_CHECK_OFF(PDMPCIDEV, abConfig);
+    GEN_CHECK_OFF(PDMPCIDEV, uDevFn);
+    GEN_CHECK_OFF(PDMPCIDEV, pszNameR3);
+    GEN_CHECK_OFF(PDMPCIDEV, pvReserved);
+    GEN_CHECK_OFF(PDMPCIDEV, Int);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions[1]);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions[VBOX_PCI_NUM_REGIONS - 1]);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions[0].addr);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions[0].size);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions[0].type);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions[0].padding);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pBusR3);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pBusR0);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pBusRC);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pfnConfigRead);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pfnConfigWrite);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.fFlags);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.uIrqPinState);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pfnBridgeConfigRead);
+    GEN_CHECK_OFF(PDMPCIDEV, Int.s.pfnBridgeConfigWrite);
+    GEN_CHECK_PADDING(PDMPCIDEV, Int, 8);
     GEN_CHECK_SIZE(PIIX3State);
     GEN_CHECK_SIZE(PCIBUS);
     GEN_CHECK_OFF(PCIBUS, iBus);
diff --git a/src/VBox/Disassembler/DisasmCore.cpp b/src/VBox/Disassembler/DisasmCore.cpp
index 37f4be9..d5adb89 100644
--- a/src/VBox/Disassembler/DisasmCore.cpp
+++ b/src/VBox/Disassembler/DisasmCore.cpp
@@ -2848,7 +2848,7 @@ static int disInstrWorker(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pc
  * @param   enmCpuMode      The CPU mode.
  * @param   fFilter         The instruction filter settings.
  * @param   pfnReadBytes    The byte reader, can be NULL.
- * @param   pvUser          The the user data for the reader.
+ * @param   pvUser          The user data for the reader.
  */
 DECL_FORCE_INLINE(PCDISOPCODE)
 disInitializeState(PDISSTATE pDis, RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
index 31c22eb..061a430 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
@@ -1084,9 +1084,10 @@ void printUsage(USAGECATEGORY fCategory, uint32_t fSubCategory, PRTSTREAM pStrm)
         RTStrmPrintf(pStrm,
                            "%s storagectl %s      <uuid|vmname>\n"
                      "                            --name <name>\n"
-                     "                            [--add ide|sata|scsi|floppy|sas|pcie]\n"
+                     "                            [--add ide|sata|scsi|floppy|sas|usb|pcie]\n"
                      "                            [--controller LSILogic|LSILogicSAS|BusLogic|\n"
-                     "                                          IntelAHCI|PIIX3|PIIX4|ICH6|I82078|NVMe]\n"
+                     "                                          IntelAHCI|PIIX3|PIIX4|ICH6|I82078|\n"
+                     "                            [             USB|NVMe]\n"
                      "                            [--portcount <1-n>]\n"
                      "                            [--hostiocache on|off]\n"
                      "                            [--bootable on|off]\n"
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts
index de60b70..5b6312c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts
@@ -10730,6 +10730,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts
index e952326..078e601 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts
@@ -5954,6 +5954,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniToolBar</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts
index 2bfa1b7..73a82a9 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts
@@ -10915,6 +10915,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts
index d7227f6..9d3731d 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts
@@ -10868,6 +10868,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts
index a65084c..e25b73f 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts
@@ -10309,6 +10309,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts
index 924dfad..6cbcbba 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE TS>
-<TS version="2.0" language="de_DE">
+<TS version="2.1" language="de_DE">
 <context>
     <name>@@@</name>
     <message>
@@ -2746,7 +2746,7 @@
     <name>UIInformationDataAudio</name>
     <message>
         <source>Audio</source>
-        <translation>Audio</translation>
+        <translation type="vanished">Audio</translation>
     </message>
     <message>
         <source>Host Driver</source>
@@ -2764,7 +2764,7 @@
     <message>
         <source>Display</source>
         <comment>details report</comment>
-        <translation>Anzeige</translation>
+        <translation type="vanished">Anzeige</translation>
     </message>
     <message>
         <source>Video Memory</source>
@@ -2827,7 +2827,7 @@
     <message>
         <source>General</source>
         <comment>details report</comment>
-        <translation>Allgemein</translation>
+        <translation type="vanished">Allgemein</translation>
     </message>
     <message>
         <source>Name</source>
@@ -2844,7 +2844,7 @@
     <name>UIInformationDataNetwork</name>
     <message>
         <source>Network</source>
-        <translation>Netzwerk</translation>
+        <translation type="vanished">Netzwerk</translation>
     </message>
     <message>
         <source>Bridged adapter, %1</source>
@@ -2890,7 +2890,7 @@
     <message>
         <source>Network Statistics</source>
         <comment>details report</comment>
-        <translation>Netzwerkadapter</translation>
+        <translation type="vanished">Netzwerkadapter</translation>
     </message>
 </context>
 <context>
@@ -2898,7 +2898,7 @@
     <message>
         <source>Parallel Ports</source>
         <comment>details report</comment>
-        <translation>Parallel-Ports</translation>
+        <translation type="vanished">Parallel-Ports</translation>
     </message>
     <message>
         <source>Port %1</source>
@@ -2916,7 +2916,7 @@
     <message>
         <source>Runtime Attributes</source>
         <comment>details report</comment>
-        <translation>Laufzeit-Attribute</translation>
+        <translation type="vanished">Laufzeit-Attribute</translation>
     </message>
     <message>
         <source>Not Detected</source>
@@ -2988,7 +2988,7 @@
     <name>UIInformationDataSerialPorts</name>
     <message>
         <source>Serial Ports</source>
-        <translation>Serielle Schnittstellen</translation>
+        <translation type="vanished">Serielle Schnittstellen</translation>
     </message>
     <message>
         <source>Port %1</source>
@@ -3001,7 +3001,7 @@
     <message>
         <source>Shared Folders</source>
         <comment>details report</comment>
-        <translation>Gemeinsame Ordner</translation>
+        <translation type="vanished">Gemeinsame Ordner</translation>
     </message>
     <message>
         <source>Shared Folders</source>
@@ -3013,7 +3013,7 @@
     <name>UIInformationDataStorage</name>
     <message>
         <source>Storage</source>
-        <translation>Massenspeicher</translation>
+        <translation type="vanished">Massenspeicher</translation>
     </message>
     <message>
         <source>(Optical Drive)</source>
@@ -3041,7 +3041,7 @@
     <message>
         <source>Storage Statistics</source>
         <comment>details report</comment>
-        <translation>Massenspeicher</translation>
+        <translation type="vanished">Massenspeicher</translation>
     </message>
 </context>
 <context>
@@ -3049,7 +3049,7 @@
     <message>
         <source>System</source>
         <comment>details report</comment>
-        <translation>System</translation>
+        <translation type="vanished">System</translation>
     </message>
     <message>
         <source>Enabled</source>
@@ -3157,7 +3157,7 @@
     <message>
         <source>USB</source>
         <comment>details report</comment>
-        <translation>USB</translation>
+        <translation type="vanished">USB</translation>
     </message>
     <message>
         <source>Disabled</source>
@@ -5930,6 +5930,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation>Möchten Sie die Dateien <nobr><b>%1</b></nobr> löschen?</translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniToolBar</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts
index f8045cd..02750c3 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts
@@ -6,6 +6,7 @@
     <message>
         <source>English</source>
         <comment>Native language name</comment>
+        <translatorcomment>2016-11-10</translatorcomment>
         <translation>Ελληνικά</translation>
     </message>
     <message>
@@ -100,22 +101,22 @@
     <name>QIArrowButtonPress</name>
     <message>
         <source>&Back</source>
-        <translation>&Προηγούμενο</translation>
+        <translation>Προηγούμενο</translation>
     </message>
     <message>
         <source>&Next</source>
-        <translation>&Επόμενο</translation>
+        <translation>Επόμενο</translation>
     </message>
 </context>
 <context>
     <name>QIArrowSplitter</name>
     <message>
         <source>&Back</source>
-        <translation type="vanished">&Προηγούμενο</translation>
+        <translation type="vanished">Προηγούμενο</translation>
     </message>
     <message>
         <source>&Next</source>
-        <translation type="vanished">&Επόμενο</translation>
+        <translation type="vanished">Επόμενο</translation>
     </message>
     <message>
         <source>&Details</source>
@@ -367,7 +368,7 @@
     </message>
     <message>
         <source>S&tart</source>
-        <translation>Ξεκίνημα</translation>
+        <translation>Εκκίνηση</translation>
     </message>
     <message>
         <source>S&how</source>
@@ -475,7 +476,7 @@
     </message>
     <message>
         <source>&VirtualBox</source>
-        <translation>&VirtualBox</translation>
+        <translation>VirtualBox</translation>
     </message>
     <message>
         <source>&Menu Bar</source>
@@ -592,7 +593,7 @@
     </message>
     <message>
         <source>&USB</source>
-        <translation>&USB</translation>
+        <translation>USB</translation>
     </message>
     <message>
         <source>&Logging</source>
@@ -1890,7 +1891,7 @@
     </message>
     <message>
         <source>V&RDP Authentication Library:</source>
-        <translation>Βιβλιοθήκη πιστοποίησης V&RDP:</translation>
+        <translation>Βιβλιοθήκη πιστοποίησης VRDP:</translation>
     </message>
     <message>
         <source>When checked, the host screensaver will be disabled whenever a virtual machine is running.</source>
@@ -1925,7 +1926,7 @@
     </message>
     <message>
         <source>&VirtualBox Manager</source>
-        <translation>Διαχειριστής &VirtualBox</translation>
+        <translation>Διαχειριστής VirtualBox</translation>
     </message>
     <message>
         <source>Virtual &Machine</source>
@@ -1945,7 +1946,7 @@
     <message>
         <source> (built-in)</source>
         <comment>Language</comment>
-        <translation> (εγγενές)</translation>
+        <translation> (εγγενής)</translation>
     </message>
     <message>
         <source><unavailable></source>
@@ -2382,15 +2383,15 @@
     </message>
     <message>
         <source>Supports &DHCP</source>
-        <translation>Υποστηρίζει &DHCP</translation>
+        <translation>Υποστηρίζει DHCP</translation>
     </message>
     <message>
         <source>Supports &IPv6</source>
-        <translation>Υποστηρίζει &IPv6</translation>
+        <translation>Υποστηρίζει IPv6</translation>
     </message>
     <message>
         <source>Advertise Default IPv6 &Route</source>
-        <translation>Διαλάληση του προεπιλεγμένου δρομολογητή IPv6</translation>
+        <translation>Κοινοποίηση του προεπιλεγμένου δρομολογητή IPv6</translation>
     </message>
     <message>
         <source>&Port Forwarding</source>
@@ -2410,7 +2411,7 @@
     </message>
     <message>
         <source>When checked, this network will be advertised as the default IPv6 route.</source>
-        <translation>Όταν επιλεγεί, αυτό το δίκτυο θα διαλαλείται σαν τον προεπιλεγμένο δρομολογητή IPv6.</translation>
+        <translation>Όταν επιλεγεί, αυτό το δίκτυο θα κοινοποιείται σαν τον προεπιλεγμένο δρομολογητή IPv6.</translation>
     </message>
     <message>
         <source>Displays a window to configure port forwarding rules.</source>
@@ -2650,7 +2651,7 @@
     </message>
     <message>
         <source>&Agree</source>
-        <translation>&Συμφωνώ</translation>
+        <translation>Συμφωνώ</translation>
     </message>
     <message>
         <source>&Print...</source>
@@ -2658,7 +2659,7 @@
     </message>
     <message>
         <source>&Save...</source>
-        <translation>Σώσιμο...</translation>
+        <translation>Αποθήκευση...</translation>
     </message>
     <message>
         <source>Text (*.txt)</source>
@@ -2666,7 +2667,7 @@
     </message>
     <message>
         <source>Save license to file...</source>
-        <translation>Σώστε την άδεια σε αρχείο...</translation>
+        <translation>Αποθηκεύστε την άδεια σε αρχείο...</translation>
     </message>
 </context>
 <context>
@@ -3802,7 +3803,7 @@
     </message>
     <message>
         <source>&IRQ:</source>
-        <translation>&IRQ:</translation>
+        <translation>IRQ:</translation>
     </message>
     <message>
         <source>I/O Po&rt:</source>
@@ -3995,7 +3996,7 @@
     </message>
     <message>
         <source>&IRQ:</source>
-        <translation>&IRQ:</translation>
+        <translation>IRQ:</translation>
     </message>
     <message>
         <source>I/O Po&rt:</source>
@@ -4058,7 +4059,7 @@
     <name>UIMachineSettingsStorage</name>
     <message>
         <source><nobr><b>%1</b></nobr><br><nobr>Bus:&nbsp;&nbsp;%2</nobr><br><nobr>Type:&nbsp;&nbsp;%3</nobr></source>
-        <translation><nobr><b>%1</b></nobr><br><nobr>Δίαυλος:&nbsp;&nbsp;%2</nobr><br><nobr>Τύπος:&nbsp;&nbsp;%3</nobr></translation>
+        <translation><nobr><b>%1</b></nobr><br><nobr>Ελεγκτής:&nbsp;&nbsp;%2</nobr><br><nobr>Τύπος:&nbsp;&nbsp;%3</nobr></translation>
     </message>
     <message>
         <source>Add Controller</source>
@@ -4429,7 +4430,7 @@
     </message>
     <message>
         <source>Enable PA&E/NX</source>
-        <translation>Ενεργοποίηση PA&E/NX</translation>
+        <translation>Ενεργοποίηση PAE/NX</translation>
     </message>
     <message>
         <source>Acce&leration</source>
@@ -4465,7 +4466,7 @@
     </message>
     <message>
         <source>Hardware Clock in &UTC Time</source>
-        <translation>Ρολόι συστήματος σε ώρα &UTC</translation>
+        <translation>Ρολόι συστήματος σε ώρα UTC</translation>
     </message>
     <message>
         <source>Controls the number of virtual CPUs in the virtual machine. You need hardware virtualization support on your host system to use more than one virtual CPU.</source>
@@ -4635,15 +4636,15 @@
     </message>
     <message>
         <source>USB &1.1 (OHCI) Controller</source>
-        <translation>Ελεγκτής USB &1.1 (OHCI)</translation>
+        <translation>Ελεγκτής USB 1.1 (OHCI)</translation>
     </message>
     <message>
         <source>USB &2.0 (EHCI) Controller</source>
-        <translation>Ελεγκτής USB &2.0 (EHCI)</translation>
+        <translation>Ελεγκτής USB 2.0 (EHCI)</translation>
     </message>
     <message>
         <source>USB &3.0 (xHCI) Controller</source>
-        <translation>Ελεγκτής USB &3.0 (xHCI)</translation>
+        <translation>Ελεγκτής USB 3.0 (xHCI)</translation>
     </message>
     <message>
         <source>USB 2.0/3.0 is currently enabled for this virtual machine. However, this requires the <i>%1</i> to be installed. Please install the Extension Pack from the VirtualBox download site or disable USB 2.0/3.0 to be able to start the machine.</source>
@@ -4845,7 +4846,7 @@
     </message>
     <message>
         <source><p>You are about to change the settings of the disk image file <b>%1</b>.</p><p>Please choose one of the following modes and press <b>%2</b> to proceed or <b>%3</b> otherwise.</p></source>
-        <translation><p>Πρόκειται να αλλάξετε τις ρυθμίσεις του αρχείου εικόνας δίσκου <b>%1</b>.</p><p>Επιλέξτε έναν από τις παρακάτω λειτουργίες και πατήστε <b>%2</b> για να προχωρήσετε ή <b>%3</b> αλλιώς.</p></translation>
+        <translation><p>Πρόκειται να αλλάξετε τις ρυθμίσεις του αρχείου εικόνας δίσκου <b>%1</b>.</p><p>Επιλέξτε μία από τις παρακάτω λειτουργίες και πατήστε <b>%2</b> για να προχωρήσετε ή <b>%3</b> αλλιώς.</p></translation>
     </message>
     <message>
         <source>Choose mode:</source>
@@ -5182,7 +5183,7 @@
     <message>
         <source>Keep</source>
         <comment>hard disk storage</comment>
-        <translation>Κράτηση</translation>
+        <translation>Διατήρηση</translation>
     </message>
     <message>
         <source>Failed to delete the storage unit of the hard disk <b>%1</b>.</source>
@@ -5331,7 +5332,7 @@
     </message>
     <message>
         <source><p>You are about to add a virtual hard disk to controller <b>%1</b>.</p><p>Would you like to create a new, empty file to hold the disk contents or select an existing one?</p></source>
-        <translation><p>Θα προσθέσετε ένα εικονικό σκληρό δίσκο στον ελεγκτή <b>%1</b>.</p><p>Θέλετε να δημιουργήσετε ένα καινούριο, κενό αρχείο με τα περιεχόμενα του δίσκου ή να επιλέξετε ένα υπάρχον;</p></translation>
+        <translation><p>Θα προσθέσετε ένα εικονικό σκληρό δίσκο στον ελεγκτή <b>%1</b>.</p><p>Θέλετε να δημιουργήσετε ένα καινούριο, κενό αρχείο για τα περιεχόμενα του δίσκου ή να επιλέξετε ένα υπάρχον;</p></translation>
     </message>
     <message>
         <source><p>You are about to add a new floppy drive to controller <b>%1</b>.</p><p>Would you like to choose a virtual floppy disk to put in the drive or to leave it empty for now?</p></source>
@@ -5948,17 +5949,21 @@
         <translation><p>Αποτυχία δημιουργίας του αντικειμένου COM του VirtualBoxClient.</p><p>Η εφαρμογή θα τερματιστεί τώρα.</p></translation>
     </message>
     <message>
+        <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
+        <translation>Θέλετε να διαγράψετε το κατεβασμένο αρχείο <nobr><b>%1</b></nobr>;</translation>
+    </message>
+    <message>
         <source>Delete</source>
         <comment>extension pack</comment>
-        <translation type="unfinished">Διαγραφή</translation>
+        <translation>Διαγραφή</translation>
     </message>
     <message>
-        <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
+        <translation>Θέλετε να διαγράψετε την ακόλουθη λίστα αρχείων <nobr><b>%1</b></nobr>;</translation>
     </message>
     <message>
-        <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation>Ο λόγος γι' αυτό το λάθος είναι μάλλον λάθος δικαιώματα της υποδοχής του δαίμονα IPC εξ αιτίας προβλημάτων στην εγκατάσταση. Ελέξτε τα δικαιώματα στα <font color=blue>'/tmp'</font> και <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
     </message>
 </context>
 <context>
@@ -6395,11 +6400,11 @@
     <name>UISettingsSerializerProgress</name>
     <message>
         <source>Loading Settings...</source>
-        <translation>Φορτώνονται οι Ρυθμίσεις...</translation>
+        <translation>Φόρτωση των ρυθμίσεων...</translation>
     </message>
     <message>
         <source>Saving Settings...</source>
-        <translation>Σώζονται οι Ρυθμίσεις...</translation>
+        <translation>Αποθήκευση των ρυθμίσεων...</translation>
     </message>
 </context>
 <context>
@@ -6557,7 +6562,7 @@
     </message>
     <message>
         <source>&Snapshots</source>
-        <translation>&Στιγμιότυπα</translation>
+        <translation>Στιγμιότυπα</translation>
     </message>
 </context>
 <context>
@@ -6706,7 +6711,7 @@
     </message>
     <message>
         <source>&Previous</source>
-        <translation>&Προηγούμενο</translation>
+        <translation>Προηγούμενο</translation>
     </message>
     <message>
         <source>Search for the previous occurrence of the string</source>
@@ -6714,7 +6719,7 @@
     </message>
     <message>
         <source>&Next</source>
-        <translation>&Επόμενο</translation>
+        <translation>Επόμενο</translation>
     </message>
     <message>
         <source>Search for the next occurrence of the string</source>
@@ -6738,7 +6743,7 @@
     </message>
     <message>
         <source>Save VirtualBox Log As</source>
-        <translation>Σώστε την καταγραφή VirtualBox ως</translation>
+        <translation>Αποθηκεύστε την καταγραφή VirtualBox ως</translation>
     </message>
     <message>
         <source>%1 - VirtualBox Log Viewer</source>
@@ -6750,7 +6755,7 @@
     </message>
     <message>
         <source>&Save</source>
-        <translation>Σώσιμο</translation>
+        <translation>Αποθήκευση</translation>
     </message>
     <message>
         <source>Close</source>
@@ -7039,7 +7044,7 @@
     </message>
     <message>
         <source>Sun &Cloud</source>
-        <translation>Sun &Cloud</translation>
+        <translation>Sun Cloud</translation>
     </message>
     <message>
         <source>&Simple Storage System (S3)</source>
@@ -7180,7 +7185,7 @@
     </message>
     <message>
         <source>Start</source>
-        <translation>Ξεκίνημα</translation>
+        <translation>Εκκίνηση</translation>
     </message>
     <message>
         <source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from and should contain the operating system you wish to install on the virtual machine if you want to do that now. The disk will be ejected from the virtual drive automatically next time you switch the virtual machine off, but you can also do this yourself if needed u [...]
@@ -8481,17 +8486,17 @@
     <message>
         <source>Immutable</source>
         <comment>MediumType</comment>
-        <translation>Αμετάβλητος</translation>
+        <translation>Αμετάβλητο</translation>
     </message>
     <message>
         <source>Writethrough</source>
         <comment>MediumType</comment>
-        <translation>Άφθαρτος</translation>
+        <translation>Άφθαρτο</translation>
     </message>
     <message>
         <source>Shareable</source>
         <comment>MediumType</comment>
-        <translation>Διαμοιρασμένος</translation>
+        <translation>Διαμοιρασμένο</translation>
     </message>
     <message>
         <source>Readonly</source>
@@ -9066,11 +9071,11 @@
     </message>
     <message>
         <source>I &Agree</source>
-        <translation>&Συμφωνώ</translation>
+        <translation>Συμφωνώ</translation>
     </message>
     <message>
         <source>I &Disagree</source>
-        <translation>&Διαφωνώ</translation>
+        <translation>Διαφωνώ</translation>
     </message>
 </context>
 <context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts
index 4aa15cf..d098023 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts
@@ -11083,6 +11083,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
index c916afe..aa0e8c1 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
@@ -4,7 +4,7 @@
 <context>
     <name>@@@</name>
     <message>
-        <location filename="../src/globals/VBoxGlobal.cpp" line="+2064"/>
+        <location filename="../src/globals/VBoxGlobal.cpp" line="+2065"/>
         <source>English</source>
         <comment>Native language name</comment>
         <translation>Euskara</translation>
@@ -175,7 +175,7 @@
     <name>QIMessageBox</name>
     <message>
         <location filename="../src/extensions/QIMessageBox.cpp" line="+301"/>
-        <location filename="../src/globals/UIMessageCenter.cpp" line="+1796"/>
+        <location filename="../src/globals/UIMessageCenter.cpp" line="+1801"/>
         <location filename="../src/widgets/UIPopupPaneButtonPane.cpp" line="+180"/>
         <source>OK</source>
         <translation>Ongi</translation>
@@ -7797,52 +7797,57 @@
 <context>
     <name>UIMessageCenter</name>
     <message>
-        <location filename="../src/globals/UIMessageCenter.cpp" line="-1517"/>
-        <location line="+2642"/>
+        <location filename="../src/globals/UIMessageCenter.cpp" line="-1522"/>
+        <location line="+2647"/>
         <source>VirtualBox - Information</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - Argibideak</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Question</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - Galdera</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Warning</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - Ohartarazpena</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Error</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - Akatsa</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Critical Error</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - Akats Larria</translation>
     </message>
     <message>
-        <location line="-2501"/>
+        <location line="-2506"/>
         <source><p>Failed to create the VirtualBoxClient COM object.</p><p>The application will now terminate.</p></source>
         <translation><p>Hutsegitea VirtualBox COM objetua sortzerakoan.</p><p>Orain aplikazioak amaitu egingo du.</p></translation>
     </message>
     <message>
-        <location line="+8"/>
+        <location line="+7"/>
         <source><p>Failed to acquire the VirtualBox COM object.</p><p>The application will now terminate.</p></source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+101"/>
+        <location line="+4"/>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+103"/>
         <source>Failed to set the global VirtualBox extra data for key <i>%1</i> to value <i>{%2}</i>.</source>
         <translation>Hutsegitea VirtualBox gain datuak ezartzerakoan <i>%1</i>-rako <i>{%2}</i> balioan.</translation>
     </message>
@@ -8135,7 +8140,7 @@
         <translation>Hutsegitea <tt>%1</tt> irekitzerakoan. Zihurtatu zure mahaigin inguruak mota honetako URL-ak egoki kudeatu ditzakeela.</translation>
     </message>
     <message>
-        <location line="-110"/>
+        <location line="-115"/>
         <source><p>Failed to initialize COM or to find the VirtualBox COM server. Most likely, the VirtualBox server is not running or failed to start.</p><p>The application will now terminate.</p></source>
         <translation><p>Hutsegitea COM abiaraztean edo VirtualBox COM zerbitzaria aurkitzerakoan. Zihurrenik VirtualBox zerbitzaria ez dago ekinean edo huts egin du abiatzean.</p><p>Orain aplikazioak amaitu egingo du.</p></translation>
     </message>
@@ -8144,7 +8149,7 @@
         <translation type="obsolete"><p>Hutsegitea VirtualBox COM objetua sortzerakoan.</p><p>Orain aplikazioak amaitu egingo du.</p></translation>
     </message>
     <message>
-        <location line="+626"/>
+        <location line="+631"/>
         <source>Failed to set global VirtualBox properties.</source>
         <translation>Hutsegitea VirtualBox ezaugarri orokorrak ezartzerakoan.</translation>
     </message>
@@ -8702,7 +8707,7 @@
         <translation>Jadanik badaude hurrengo agiriak:<br /><br />%1<br /><br />Zihur zaude ordeztea nahi dituzula? Hauek ordezteak beren edukiak gainidaztea eragingo du.</translation>
     </message>
     <message>
-        <location line="-2074"/>
+        <location line="-2079"/>
         <source>You are running a prerelease version of VirtualBox. This version is not suitable for production use.</source>
         <translation>VirtualBox aurreargitalpen bertsio bat ari zara erabiltzen. Bertsio hau ez da ekoizpen erabilpenerako.</translation>
     </message>
@@ -8712,7 +8717,7 @@
         <translation>Gonbidatua ACPI indar botoiarekin itzaltzen saiatzen ari zara. Hau oraingoz ezinezkoa da gonbidatuak ez duelako software itzalketa sostengatzen.</translation>
     </message>
     <message>
-        <location filename="../src/globals/UIMessageCenter.cpp" line="+1422"/>
+        <location filename="../src/globals/UIMessageCenter.cpp" line="+1427"/>
         <source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Your 64-bit guest will fail to detect a 64-bit CPU and will not be able to boot.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
         <translation><p>VT-x/AMD-V hardware bizkorpena gaitu egin da, baina ez dago eraginkor. Zure 64-biteko gonbidatuak huts egingo du 64-bit CPU bat atzematerakoan eta ez da abiatzeko gai izango.</p><p>Mesedez zihurtatu VT-x/AMD-V egoki gaituta duzula zure hostalari ordenagailuaren BIOS-ean.</p></translation>
     </message>
@@ -8812,7 +8817,7 @@
         <translation>Hutsegitea agiria kentzerakoan.</translation>
     </message>
     <message>
-        <location line="-1239"/>
+        <location line="-1244"/>
         <source>You seem to have the USBFS filesystem mounted at /sys/bus/usb/drivers. We strongly recommend that you change this, as it is a severe mis-configuration of your system which could cause USB devices to fail in unexpected ways.</source>
         <translation>Dirudienez USBFS agiri-sistema duzu muntatuta honela: /sys/bus/usb/drivers. Hau aldatzea gomendatzen dizugu, zure sistemaren itxurapen-oker larria denez eta USB gailuek ustekabeko moduan huts egitea eragin dezakeelako.</translation>
     </message>
@@ -8827,7 +8832,7 @@
         <translation>VirtualBox eraiketa ESPERIMENTAL bat erabiltzen ari zara. Bertsio hau ez da ekoizpen erabilpenerako.</translation>
     </message>
     <message>
-        <location line="+43"/>
+        <location line="+48"/>
         <source><p>Could not find a language file for the language <b>%1</b> in the directory <b><nobr>%2</nobr></b>.</p><p>The language will be temporarily reset to the system default language. Please go to the <b>Preferences</b> window which you can open from the <b>File</b> menu of the VirtualBox Manager window, and select one of the existing languages on the <b>Language</b> page.</p></source>
         <translation><p>Ezin da <b>%1</b> hizkuntzarako hizkuntza agiria aurkitu <b><nobr>%2</nobr></b> zuzenbidean.</p><p>Hizkuntza aldibaterako sistemaren berezko hizkuntzan berrezarriko da. Mesedez joan <b>Hobespenak</b> leihora VirtualBox Kudeatzaile leihoko <b>Agiria</b> menutik ireki dezakezuna, eta hautatu <b>Hizkuntza</b> orrialdean badagoen hizkuntzetako bat.</p></translation>
     </message>
@@ -9256,12 +9261,12 @@
         <translation type="obsolete">Ongi</translation>
     </message>
     <message>
-        <location line="-1701"/>
+        <location line="-1706"/>
         <source><p>Failed to initialize COM because the VirtualBox global configuration directory <b><nobr>%1</nobr></b> is not accessible. Please check the permissions of this directory and of its parent directory.</p><p>The application will now terminate.</p></source>
         <translation><p>Hutsegitea COM abiarazterakoan <b><nobr>%1</nobr></b> VirtualBox-en itxurapen orokorraren zuzenbidea ez dagoelako eskuragarri. Mesedez egiaztatu zuzenbide honen eta bere gaineko zuzenbidearen baimenak.</p><p>Aplikazioak orain amaitu egingo du.</p></translation>
     </message>
     <message>
-        <location line="+200"/>
+        <location line="+205"/>
         <source><p>You are about to remove following virtual machine items from the machine list:</p><p><b>%1</b></p><p>Do you wish to proceed?</p></source>
         <translation><p>Hurrengo makina birtual gaiak kentzear zaude makinaren zerrendatik:</p><p><b>%1</b></p><p>Jarraitzea nahi duzu?</p></translation>
     </message>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts
index 4b297ab..428f664 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts
@@ -8145,6 +8145,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniToolBar</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts
index e82df41..57e414c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts
@@ -8800,6 +8800,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts
index 83c38a8..06550ea 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts
@@ -9671,6 +9671,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts
index 4202a0d..257d843 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts
@@ -8688,6 +8688,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts
index 400e765..68edf50 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts
@@ -6285,6 +6285,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniToolBar</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts
index 90ed2a0..3d38c2a 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts
@@ -10714,6 +10714,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
index 6b5f822..52bf820 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
@@ -9916,6 +9916,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts
index ee34248..8a47920 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts
@@ -11599,14 +11599,18 @@ p, li { white-space: pre-wrap; }
     <message>
         <source>Delete</source>
         <comment>extension pack</comment>
-        <translation type="unfinished"></translation>
+        <translation>Elimina</translation>
     </message>
     <message>
         <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <translation>Vuoi eliminare il file scaricato <nobr><b>%1</b></nobr>? </translation>
     </message>
     <message>
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
+        <translation>Vuoi eliminare il seguente elenco di file <nobr><b>%1</b></nobr>?</translation>
+    </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
         <translation type="unfinished"></translation>
     </message>
 </context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts
index 2cce1f6..e03ac0d 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts
@@ -11030,6 +11030,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts
index ee4f53d..b19cc92 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts
@@ -8736,6 +8736,10 @@ medium</comment>
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts
index 55f231b..0bc0de3 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts
@@ -10861,6 +10861,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts
index 481baa2..ace2a31 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts
@@ -9596,6 +9596,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts
index 0c3e00f..2e7db9c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts
@@ -94,22 +94,22 @@
     </message>
     <message>
         <source>The VirtualBox Linux kernel driver (vboxdrv) is either not loaded or there is a permission problem with /dev/vboxdrv. Please reinstall the kernel module by executing<br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/>as root.</source>
-        <translation type="unfinished"></translation>
+        <translation>De VirtualBox kerneldriver (vboxdrv) is niet geladen of er is een probleem met permissies op /dev/vboxdrv. Herinstalleer de kernelmodule als root met het commando <br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/>.</translation>
     </message>
     <message>
         <source>The VirtualBox kernel modules do not match this version of VirtualBox. The installation of VirtualBox was apparently not successful. Executing<br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/>may correct this. Make sure that you do not mix the OSE version and the PUEL version of VirtualBox.</source>
-        <translation type="unfinished"></translation>
+        <translation>De VirtualBox kernelmodules passen niet bij deze versie van VirtualBox. De installatie van VirtualBox is kennelijk niet goed gelukt. Uitvoeren van <br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/> zou dit kunnen corrigeren. Controleer of u de OSE versie en de PUEL versie van VirtualBox niet hebt vermengd.</translation>
     </message>
 </context>
 <context>
     <name>QIArrowButtonPress</name>
     <message>
         <source>&Back</source>
-        <translation type="unfinished">&Vorige</translation>
+        <translation>&Vorige</translation>
     </message>
     <message>
         <source>&Next</source>
-        <translation type="unfinished">&Volgende</translation>
+        <translation>&Volgende</translation>
     </message>
 </context>
 <context>
@@ -124,11 +124,11 @@
     </message>
     <message>
         <source>&Details</source>
-        <translation type="unfinished">&Details</translation>
+        <translation>&Details</translation>
     </message>
     <message>
         <source>&Details (%1 of %2)</source>
-        <translation type="unfinished">&Details (%1 van %2)</translation>
+        <translation>&Details (%1 van %2)</translation>
     </message>
 </context>
 <context>
@@ -1378,39 +1378,40 @@
     </message>
     <message>
         <source>&VirtualBox Bug Tracker...</source>
-        <translation type="unfinished"></translation>
+        <translation>&VirtualBox Bug Tracker...</translation>
     </message>
     <message>
         <source>Open the browser and go to the VirtualBox product bug tracker</source>
-        <translation type="unfinished"></translation>
+        <translation>Open de browser en ga naar de VirtualBox-produktbugtracker</translation>
     </message>
     <message>
         <source>&VirtualBox Forums...</source>
-        <translation type="unfinished"></translation>
+        <translation>&VirtualBox Forums...</translation>
     </message>
     <message>
         <source>Open the browser and go to the VirtualBox product forums</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>ok, ok, het is eigenlijk fora....</translatorcomment>
+        <translation>Open de browser en ga naar de VirtualBox-produktforums</translation>
     </message>
     <message>
         <source>&Oracle Web Site...</source>
-        <translation type="unfinished"></translation>
+        <translation>&Oracle Web Site...</translation>
     </message>
     <message>
         <source>Open the browser and go to the Oracle web site</source>
-        <translation type="unfinished"></translation>
+        <translation>Open de browser en ga naar de website van Oracle</translation>
     </message>
     <message>
         <source>&Detach GUI</source>
-        <translation type="unfinished"></translation>
+        <translation>GUI &loskoppelen</translation>
     </message>
     <message>
         <source>Detach the GUI from headless VM</source>
-        <translation type="unfinished"></translation>
+        <translation>GUI loskoppelen van headless VM</translation>
     </message>
     <message>
         <source>Disable Dock Icon Overlay</source>
-        <translation type="unfinished"></translation>
+        <translation>Uitschakelen dockpictogramoverschrijving</translation>
     </message>
 </context>
 <context>
@@ -1624,73 +1625,73 @@
     <name>UIApplianceUnverifiedCertificateViewer</name>
     <message>
         <source>Unverifiable Certificate! Continue?</source>
-        <translation type="unfinished"></translation>
+        <translation>Het certificaat is niet te verifiëren. Doorgaan?</translation>
     </message>
     <message>
         <source><b>The appliance is signed by an unverified self signed certificate issued by '%1'. We recommend to only proceed with the importing if you are sure you should trust this entity.</b></source>
-        <translation type="unfinished"></translation>
+        <translation><b>De appliance is getekend door een ongeverifieerd 'self signed certificate' uitgegeven door '%1'. We raden aan alleen met importeren door te gaan als je echt weet met wie je te maken hebt.</b></translation>
     </message>
     <message>
         <source><b>The appliance is signed by an unverified certificate issued to '%1'. We recommend to only proceed with the importing if you are sure you should trust this entity.</b></source>
-        <translation type="unfinished"></translation>
+        <translation><b>De appliance is getekend door een ongeverifieerd certificaat uitgegeven door '%1'. We raden aan alleen met importeren door te gaan als je echt weet met wie je te maken hebt.</b></translation>
     </message>
     <message>
         <source>True</source>
-        <translation type="unfinished"></translation>
+        <translation>Waar</translation>
     </message>
     <message>
         <source>False</source>
-        <translation type="unfinished"></translation>
+        <translation>Onwaar</translation>
     </message>
     <message>
         <source><tr><td>%1:</td><td>%2</td></tr></source>
         <comment>key: value</comment>
-        <translation type="unfinished"></translation>
+        <translation><tr><td>%1:</td><td>%2</td></tr></translation>
     </message>
     <message>
         <source>Issuer</source>
-        <translation type="unfinished"></translation>
+        <translation>Uitgever</translation>
     </message>
     <message>
         <source>Subject</source>
-        <translation type="unfinished"></translation>
+        <translation>Onderwerp</translation>
     </message>
     <message>
         <source>Not Valid Before</source>
-        <translation type="unfinished"></translation>
+        <translation>Niet geldig voor</translation>
     </message>
     <message>
         <source>Not Valid After</source>
-        <translation type="unfinished"></translation>
+        <translation>Niet geldig na</translation>
     </message>
     <message>
         <source>Serial Number</source>
-        <translation type="unfinished"></translation>
+        <translation>Serienummer</translation>
     </message>
     <message>
         <source>Self-Signed</source>
-        <translation type="unfinished"></translation>
+        <translation>Self-Signed</translation>
     </message>
     <message>
         <source>Authority (CA)</source>
-        <translation type="unfinished"></translation>
+        <translation>Authority (CA)</translation>
     </message>
     <message>
         <source>Public Algorithm</source>
-        <translation type="unfinished"></translation>
+        <translation>Publiek algorithme</translation>
     </message>
     <message>
         <source>%1 (%2)</source>
         <comment>value (clarification)</comment>
-        <translation type="unfinished"></translation>
+        <translation>%1 (%2)</translation>
     </message>
     <message>
         <source>Signature Algorithm</source>
-        <translation type="unfinished"></translation>
+        <translation>Signatuur algorithme</translation>
     </message>
     <message>
         <source>X.509 Version Number</source>
-        <translation type="unfinished"></translation>
+        <translation>X.509 Versienummer</translation>
     </message>
 </context>
 <context>
@@ -2409,7 +2410,7 @@
     <name>UIEmptyFilePathSelector</name>
     <message>
         <source>Choose...</source>
-        <translation type="unfinished">Kiezen...</translation>
+        <translation>Kiezen...</translation>
     </message>
 </context>
 <context>
@@ -2585,55 +2586,55 @@
     <name>UIFilePathSelector</name>
     <message>
         <source>&Copy</source>
-        <translation type="unfinished">&Kopiëren</translation>
+        <translation>&Kopiëren</translation>
     </message>
     <message>
         <source>Other...</source>
-        <translation type="unfinished">Andere...</translation>
+        <translation>Andere...</translation>
     </message>
     <message>
         <source>Reset</source>
-        <translation type="unfinished"></translation>
+        <translation>Reset</translation>
     </message>
     <message>
         <source>Displays a window to select a different folder.</source>
-        <translation type="unfinished">Toont een venster waarin een andere map kan worden gekozen.</translation>
+        <translation>Toont een venster waarin een andere map kan worden gekozen.</translation>
     </message>
     <message>
         <source>Resets the folder path to the default value.</source>
-        <translation type="unfinished">Zet het pad naar de map terug op de standaardwaarde.</translation>
+        <translation>Zet het pad naar de map terug op de standaardwaarde.</translation>
     </message>
     <message>
         <source>Displays a window to select a different file.</source>
-        <translation type="unfinished">Toont een venster waarin een ander bestand kan worden gekozen.</translation>
+        <translation>Toont een venster waarin een ander bestand kan worden gekozen.</translation>
     </message>
     <message>
         <source>Resets the file path to the default value.</source>
-        <translation type="unfinished">Zet het pad naar het bestand terug op de standaardwaarde.</translation>
+        <translation>Zet het pad naar het bestand terug op de standaardwaarde.</translation>
     </message>
     <message>
         <source><reset to default></source>
-        <translation type="unfinished"><standaard terugzetten></translation>
+        <translation><standaard terugzetten></translation>
     </message>
     <message>
         <source>The actual default path value will be displayed after accepting the changes and opening this window again.</source>
-        <translation type="unfinished">Het daadwerkelijke standaardpad zal worden getoond na acceptatie van de veranderingen en het heropenen van dit venster.</translation>
+        <translation>Het daadwerkelijke standaardpad zal worden getoond na acceptatie van de veranderingen en het heropenen van dit venster.</translation>
     </message>
     <message>
         <source><not selected></source>
-        <translation type="unfinished"><niet geselecteerd></translation>
+        <translation><niet geselecteerd></translation>
     </message>
     <message>
         <source>Please use the <b>Other...</b> item from the drop-down list to select a path.</source>
-        <translation type="unfinished">Gebruik het <b>Andere...</b> item uit de keuzelijst om het gewenste pad te selecteren.</translation>
+        <translation>Gebruik het <b>Andere...</b> item uit de keuzelijst om het gewenste pad te selecteren.</translation>
     </message>
     <message>
         <source>Holds the folder path.</source>
-        <translation type="unfinished">Bevat het pad naar de map.</translation>
+        <translation>Bevat het pad naar de map.</translation>
     </message>
     <message>
         <source>Holds the file path.</source>
-        <translation type="unfinished">Bevat het bestandspad.</translation>
+        <translation>Bevat het bestandspad.</translation>
     </message>
 </context>
 <context>
@@ -4028,7 +4029,7 @@
     </message>
     <message>
         <source>Host interface <b>%1</b> does not currently have a valid IPv6 network mask prefix length.</source>
-        <translation type="unfinished"></translation>
+        <translation>Hostinterface <b>%1</b> heeft op dit moment geen geldige IPv4-netwerkmaskerprefixlengte.</translation>
     </message>
 </context>
 <context>
@@ -4399,27 +4400,27 @@
     </message>
     <message>
         <source>When chosen, VirtualBox will try to auto-detect host proxy settings for tasks like downloading Guest Additions from the network or checking for updates.</source>
-        <translation type="unfinished"></translation>
+        <translation>Als dit is gekozen zal VirtualBox proberen de proxy-instellingen zelf te ontdekken. Deze instellingen worden gebruikt bij bijvoorbeeld downloaden van Guest Additions van het netwerk of controleren op updates.</translation>
     </message>
     <message>
         <source>&Auto-detect Host Proxy Settings</source>
-        <translation type="unfinished"></translation>
+        <translation>&Autodetectie hostproxy-instellingen</translation>
     </message>
     <message>
         <source>When chosen, VirtualBox will use direct Internet connection for tasks like downloading Guest Additions from the network or checking for updates.</source>
-        <translation type="unfinished"></translation>
+        <translation>Als dit is gekozen zal VirtualBox de directe internetconnectie gebruiken bij bijvoorbeeld downloaden van Guest Additions van het netwerk of controleren op updates.</translation>
     </message>
     <message>
         <source>&Direct Connection to the Internet</source>
-        <translation type="unfinished"></translation>
+        <translation>&Directe internetconnectie</translation>
     </message>
     <message>
         <source>When chosen, VirtualBox will use the proxy settings supplied for tasks like downloading Guest Additions from the network or checking for updates.</source>
-        <translation type="unfinished"></translation>
+        <translation>Als dit is gekozen zal VirtualBox de opgegeven proxy gebruiken bij bijvoorbeeld downloaden van Guest Additions van het netwerk of controleren op updates.</translation>
     </message>
     <message>
         <source>&Manual Proxy Configuration</source>
-        <translation type="unfinished"></translation>
+        <translation>Hand&matige proxyconfiguratie</translation>
     </message>
 </context>
 <context>
@@ -4866,12 +4867,12 @@
     <message>
         <source>Host Driver</source>
         <comment>details report (audio)</comment>
-        <translation type="unfinished"></translation>
+        <translation>Hoststuurprogramma</translation>
     </message>
     <message>
         <source>Controller</source>
         <comment>details report (audio)</comment>
-        <translation type="unfinished">Controller</translation>
+        <translation>Controller</translation>
     </message>
 </context>
 <context>
@@ -4884,57 +4885,57 @@
     <message>
         <source>Video Memory</source>
         <comment>details report</comment>
-        <translation type="unfinished">Videogeheugen</translation>
+        <translation>Videogeheugen</translation>
     </message>
     <message>
         <source>Screens</source>
         <comment>details report</comment>
-        <translation type="unfinished">Beeldschermen</translation>
+        <translation>Beeldschermen</translation>
     </message>
     <message>
         <source>Enabled</source>
         <comment>details report (3D Acceleration)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (3D Acceleration)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>3D Acceleration</source>
         <comment>details report</comment>
-        <translation type="unfinished">3D-acceleratie</translation>
+        <translation>3D-acceleratie</translation>
     </message>
     <message>
         <source>Enabled</source>
         <comment>details report (2D Video Acceleration)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (2D Video Acceleration)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>2D Video Acceleration</source>
         <comment>details report</comment>
-        <translation type="unfinished">2D-videoversnelling</translation>
+        <translation>2D-videoversnelling</translation>
     </message>
     <message>
         <source>Remote Desktop Server Port</source>
         <comment>details report (VRDE Server)</comment>
-        <translation type="unfinished"></translation>
+        <translation>Remote Desktop Serverpoort</translation>
     </message>
     <message>
         <source>Remote Desktop Server</source>
         <comment>details report (VRDE Server)</comment>
-        <translation type="unfinished"></translation>
+        <translation>Remote Desktop Server</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (VRDE Server)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
 </context>
 <context>
@@ -4947,12 +4948,12 @@
     <message>
         <source>Name</source>
         <comment>details report</comment>
-        <translation type="unfinished">Naam</translation>
+        <translation>Naam</translation>
     </message>
     <message>
         <source>OS Type</source>
         <comment>details report</comment>
-        <translation type="unfinished"></translation>
+        <translation>OS-type</translation>
     </message>
 </context>
 <context>
@@ -4964,43 +4965,43 @@
     <message>
         <source>Bridged adapter, %1</source>
         <comment>details report (network)</comment>
-        <translation type="unfinished"></translation>
+        <translation>Bridged adapter, %1</translation>
     </message>
     <message>
         <source>Internal network, '%1'</source>
         <comment>details report (network)</comment>
-        <translation type="unfinished">Intern netwerk, '%1'</translation>
+        <translation>Intern netwerk, '%1'</translation>
     </message>
     <message>
         <source>Host-only adapter, '%1'</source>
         <comment>details report (network)</comment>
-        <translation type="unfinished">Host-only adapter, '%1'</translation>
+        <translation>Host-only adapter, '%1'</translation>
     </message>
     <message>
         <source>Generic, '%1'</source>
         <comment>details report (network)</comment>
-        <translation type="unfinished">Generiek, '%1'</translation>
+        <translation>Generiek, '%1'</translation>
     </message>
     <message>
         <source>NAT network, '%1'</source>
         <comment>details report (network)</comment>
-        <translation type="unfinished">NAT-netwerk, '%1'</translation>
+        <translation>NAT-netwerk, '%1'</translation>
     </message>
     <message>
         <source>Adapter %1</source>
         <comment>details report (network)</comment>
-        <translation type="unfinished">Adapter %1</translation>
+        <translation>Adapter %1</translation>
     </message>
 </context>
 <context>
     <name>UIInformationDataNetworkStatistics</name>
     <message>
         <source>Data Transmitted</source>
-        <translation type="unfinished">Verzonden data</translation>
+        <translation>Verzonden data</translation>
     </message>
     <message>
         <source>Data Received</source>
-        <translation type="unfinished">Ontvangen data</translation>
+        <translation>Ontvangen data</translation>
     </message>
     <message>
         <source>Network Statistics</source>
@@ -5013,12 +5014,12 @@
     <message>
         <source>Port %1</source>
         <comment>details report (parallel ports)</comment>
-        <translation type="unfinished">Poort %1</translation>
+        <translation>Poort %1</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (parallel ports)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
 </context>
 <context>
@@ -5031,67 +5032,67 @@
     <message>
         <source>Not Detected</source>
         <comment>guest additions</comment>
-        <translation type="unfinished">Niet ontdekt</translation>
+        <translation>Niet ontdekt</translation>
     </message>
     <message>
         <source>Not Detected</source>
         <comment>guest os type</comment>
-        <translation type="unfinished">Niet ontdekt</translation>
+        <translation>Niet ontdekt</translation>
     </message>
     <message>
         <source>Not Available</source>
         <comment>details report (VRDE server port)</comment>
-        <translation type="unfinished">Niet beschikbaar</translation>
+        <translation>Niet beschikbaar</translation>
     </message>
     <message>
         <source>Screen Resolution</source>
-        <translation type="unfinished">Schermresolutie</translation>
+        <translation>Schermresolutie</translation>
     </message>
     <message>
         <source>VM Uptime</source>
-        <translation type="unfinished">VM uptime</translation>
+        <translation>VM-uptime</translation>
     </message>
     <message>
         <source>Clipboard Mode</source>
-        <translation type="unfinished">Klembordmodus</translation>
+        <translation>Klembordmodus</translation>
     </message>
     <message>
         <source>Drag and Drop Mode</source>
-        <translation type="unfinished">Drag-and-drop modus</translation>
+        <translation>Drag-and-drop modus</translation>
     </message>
     <message>
         <source>VT-x/AMD-V</source>
         <comment>details report</comment>
-        <translation type="unfinished">VT-x/AMD-V</translation>
+        <translation>VT-x/AMD-V</translation>
     </message>
     <message>
         <source>Nested Paging</source>
         <comment>details report</comment>
-        <translation type="unfinished"></translation>
+        <translation>Geneste Paging</translation>
     </message>
     <message>
         <source>Unrestricted Execution</source>
         <comment>details report</comment>
-        <translation type="unfinished">Onbeperkte uitvoering</translation>
+        <translation>Onbeperkte uitvoering</translation>
     </message>
     <message>
         <source>Paravirtualization Interface</source>
         <comment>details report</comment>
-        <translation type="unfinished">Paravirtualisatie-interface</translation>
+        <translation>Paravirtualisatie-interface</translation>
     </message>
     <message>
         <source>Guest Additions</source>
-        <translation type="unfinished">Guest Additions</translation>
+        <translation>Guest Additions</translation>
     </message>
     <message>
         <source>Guest OS Type</source>
         <comment>details report</comment>
-        <translation type="unfinished">Gast OS-type</translation>
+        <translation>Gast OS-type</translation>
     </message>
     <message>
         <source>Remote Desktop Server Port</source>
         <comment>details report (VRDE Server)</comment>
-        <translation type="unfinished"></translation>
+        <translation>Remote Desktop Serverpoort</translation>
     </message>
 </context>
 <context>
@@ -5103,7 +5104,7 @@
     <message>
         <source>Port %1</source>
         <comment>details report (serial ports)</comment>
-        <translation type="unfinished">Poort %1</translation>
+        <translation>Poort %1</translation>
     </message>
 </context>
 <context>
@@ -5116,7 +5117,7 @@
     <message>
         <source>Shared Folders</source>
         <comment>details report (shared folders)</comment>
-        <translation type="unfinished">Gedeelde mappen</translation>
+        <translation>Gedeelde mappen</translation>
     </message>
 </context>
 <context>
@@ -5127,26 +5128,26 @@
     </message>
     <message>
         <source>(Optical Drive)</source>
-        <translation type="unfinished">(Optisch station)</translation>
+        <translation>(Optisch station)</translation>
     </message>
 </context>
 <context>
     <name>UIInformationDataStorageStatistics</name>
     <message>
         <source>DMA Transfers</source>
-        <translation type="unfinished">DMA overdracht</translation>
+        <translation>DMA-overdracht</translation>
     </message>
     <message>
         <source>PIO Transfers</source>
-        <translation type="unfinished">PIO-overdracht</translation>
+        <translation>PIO-overdracht</translation>
     </message>
     <message>
         <source>Data Read</source>
-        <translation type="unfinished">Gelezen data</translation>
+        <translation>Gelezen data</translation>
     </message>
     <message>
         <source>Data Written</source>
-        <translation type="unfinished">Geschreven data</translation>
+        <translation>Geschreven data</translation>
     </message>
     <message>
         <source>Storage Statistics</source>
@@ -5164,102 +5165,102 @@
     <message>
         <source>Enabled</source>
         <comment>details report (ACPI)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (ACPI)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>Enabled</source>
         <comment>details report (I/O APIC)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (I/O APIC)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>Enabled</source>
         <comment>details report (PAE/NX)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (PAE/NX)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>Base Memory</source>
         <comment>details report</comment>
-        <translation type="unfinished"></translation>
+        <translation>Basisgeheugen</translation>
     </message>
     <message>
         <source>Processor(s)</source>
         <comment>details report</comment>
-        <translation type="unfinished">Processoren</translation>
+        <translation>Processor(en)</translation>
     </message>
     <message>
         <source>Execution Cap</source>
         <comment>details report</comment>
-        <translation type="unfinished"></translation>
+        <translation>CPU-Begrenzing</translation>
     </message>
     <message>
         <source>Boot Order</source>
         <comment>details report</comment>
-        <translation type="unfinished">Opstartvolgorde</translation>
+        <translation>Opstartvolgorde</translation>
     </message>
     <message>
         <source>ACPI</source>
         <comment>details report</comment>
-        <translation type="unfinished">ACPI</translation>
+        <translation>ACPI</translation>
     </message>
     <message>
         <source>I/O APIC</source>
         <comment>details report</comment>
-        <translation type="unfinished"></translation>
+        <translation>I/O-APIC</translation>
     </message>
     <message>
         <source>PAE/NX</source>
         <comment>details report</comment>
-        <translation type="unfinished">PAE/NX</translation>
+        <translation>PAE/NX</translation>
     </message>
     <message>
         <source>Enabled</source>
         <comment>details report (VT-x/AMD-V)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (VT-x/AMD-V)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>VT-x/AMD-V</source>
         <comment>details report</comment>
-        <translation type="unfinished">VT-x/AMD-V</translation>
+        <translation>VT-x/AMD-V</translation>
     </message>
     <message>
         <source>Enabled</source>
         <comment>details report (Nested Paging)</comment>
-        <translation type="unfinished">Ingeschakeld</translation>
+        <translation>Ingeschakeld</translation>
     </message>
     <message>
         <source>Disabled</source>
         <comment>details report (Nested Paging)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>Nested Paging</source>
         <comment>details report</comment>
-        <translation type="unfinished"></translation>
+        <translation>Geneste Paging</translation>
     </message>
     <message>
         <source>Paravirtualization Interface</source>
         <comment>details report</comment>
-        <translation type="unfinished">Paravirtualisatie-interface</translation>
+        <translation>Paravirtualisatie-interface</translation>
     </message>
 </context>
 <context>
@@ -5272,17 +5273,17 @@
     <message>
         <source>Disabled</source>
         <comment>details report (USB)</comment>
-        <translation type="unfinished">Uitgeschakeld</translation>
+        <translation>Uitgeschakeld</translation>
     </message>
     <message>
         <source>Device Filters</source>
         <comment>details report (USB)</comment>
-        <translation type="unfinished">Apparaatfilters</translation>
+        <translation>Apparaatfilters</translation>
     </message>
     <message>
         <source>%1 (%2 active)</source>
         <comment>details report (USB)</comment>
-        <translation type="unfinished">%1 (%2 actief)</translation>
+        <translation>%1 (%2 actief)</translation>
     </message>
 </context>
 <context>
@@ -7064,7 +7065,7 @@
     </message>
     <message>
         <source>Add NVMe Controller</source>
-        <translation type="unfinished"></translation>
+        <translation>Toevoegen NVMe-controller</translation>
     </message>
 </context>
 <context>
@@ -7780,27 +7781,27 @@
     </message>
     <message>
         <source>This type of medium is attached directly or indirectly, preserved when taking snapshots.</source>
-        <translation type="unfinished"></translation>
+        <translation>Dit type medium is direct of indirect gekoppeld en wordt bewaard bij het nemen van snapshots.</translation>
     </message>
     <message>
         <source>This type of medium is attached indirectly, changes are wiped out the next time the virtual machine is started.</source>
-        <translation type="unfinished"></translation>
+        <translation>Dit type medium is direct gekoppeld; bij de volgende start van de virtuele machine zijn alle veranderingen verdwenen.</translation>
     </message>
     <message>
         <source>This type of medium is attached directly, ignored when taking snapshots.</source>
-        <translation type="unfinished"></translation>
+        <translation>Dit type medium is direct gekoppeld en wordt genegeerd bij het nemen van snapshots.</translation>
     </message>
     <message>
         <source>This type of medium is attached directly, allowed to be used concurrently by several machines.</source>
-        <translation type="unfinished"></translation>
+        <translation>Dit type medium is direct gekoppeld; diverse machines mogen tegelijkertijd dit medium gebruiken.</translation>
     </message>
     <message>
         <source>This type of medium is attached directly, and can be used by several machines.</source>
-        <translation type="unfinished"></translation>
+        <translation>Dit type medium is direct gekoppeld en kan door diverse machines worden gebruikt.</translation>
     </message>
     <message>
         <source>This type of medium is attached indirectly, so that one base medium can be used for several VMs which have their own differencing medium to store their modifications.</source>
-        <translation type="unfinished"></translation>
+        <translation>Dit type medium is indirect gekoppeld. Hierdoor kan één basismedium worden gebruikt voor diverse VMs met ieder hun eigen differencingmachine om modificaties op te slaan.</translation>
     </message>
 </context>
 <context>
@@ -9375,20 +9376,25 @@
     </message>
     <message>
         <source><p>Failed to acquire the VirtualBox COM object.</p><p>The application will now terminate.</p></source>
-        <translation type="unfinished"></translation>
+        <translation><p>Het is niet gelukt het VirtualBox COM-object te verkrijgen.</p><p>Het programma wordt nu afgesloten.</p></translation>
+    </message>
+    <message>
+        <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
+        <translatorcomment>gedownloade is met 1 d</translatorcomment>
+        <translation>Wilt u het gedownloade bestand <nobr><b>%1</b></nobr> verwijderen?</translation>
     </message>
     <message>
         <source>Delete</source>
         <comment>extension pack</comment>
-        <translation type="unfinished">Verwijderen</translation>
+        <translation>Verwijderen</translation>
     </message>
     <message>
-        <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
+        <translation>Wilt u de volgende lijst bestanden <nobr><b>%1</b></nobr> verwijderen?</translation>
     </message>
     <message>
-        <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation><p>De oorzaak van deze fout is vaak verkeerde permissies op de IPC-daemon-socket als gevold van een installatiefout. Controleer de permissies van <font color=blue>'/tmp'</font> en <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
     </message>
 </context>
 <context>
@@ -9466,7 +9472,7 @@
     </message>
     <message>
         <source>Holds the name of the virtual machine.</source>
-        <translation>Toont de naam van de virtuele machine.</translation>
+        <translation>De naam van de virtuele machine.</translation>
     </message>
     <message>
         <source>&Type:</source>
@@ -9486,7 +9492,7 @@
     </message>
     <message>
         <source>Holds the location of the virtual machine.</source>
-        <translation type="unfinished"></translation>
+        <translation>De locatie van de virtuele machine.</translation>
     </message>
 </context>
 <context>
@@ -9597,7 +9603,7 @@
     </message>
     <message>
         <source>Url not found on the server</source>
-        <translation type="unfinished"></translation>
+        <translation>Url werd op de server niet gevonden</translation>
     </message>
 </context>
 <context>
@@ -10554,15 +10560,15 @@
     <name>UIVMInformationDialog</name>
     <message>
         <source>%1 - Session Information</source>
-        <translation type="unfinished">%1 - Sessie-informatie</translation>
+        <translation>%1 - Sessie-informatie</translation>
     </message>
     <message>
         <source>Configuration &Details</source>
-        <translation type="unfinished">Configuratie&details</translation>
+        <translation>Configuratie&details</translation>
     </message>
     <message>
         <source>&Runtime Information</source>
-        <translation type="unfinished">&Runtime-informatie</translation>
+        <translation>&Runtime-informatie</translation>
     </message>
 </context>
 <context>
@@ -10650,15 +10656,15 @@
     </message>
     <message>
         <source>Filter</source>
-        <translation type="unfinished"></translation>
+        <translation>Filter</translation>
     </message>
     <message>
         <source>Enter filtering string here</source>
-        <translation type="unfinished"></translation>
+        <translation>Geef een filtertekst op</translation>
     </message>
     <message>
         <source>Fil&ter</source>
-        <translation type="unfinished"></translation>
+        <translation>Fil&ter</translation>
     </message>
 </context>
 <context>
@@ -11265,31 +11271,32 @@
     </message>
     <message>
         <source>Appliance is not signed</source>
-        <translation type="unfinished"></translation>
+        <translation>Appliance is niet getekend</translation>
     </message>
     <message>
         <source>Appliance signed by %1 (trusted)</source>
-        <translation type="unfinished"></translation>
+        <translation>Appliance getekend door %1 (trusted)</translation>
     </message>
     <message>
         <source>Appliance signed by %1 (expired!)</source>
-        <translation type="unfinished"></translation>
+        <translation>Appliance getekend door %1 (verlopen!)</translation>
     </message>
     <message>
         <source>Unverified signature by %1!</source>
-        <translation type="unfinished"></translation>
+        <translation>Niet-geverifieerde signatuur door %1!</translation>
     </message>
     <message>
         <source>Self signed by %1 (trusted)</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>Self signed is een begrip :/</translatorcomment>
+        <translation>Self signed door %1 (trusted)</translation>
     </message>
     <message>
         <source>Self signed by %1 (expired!)</source>
-        <translation type="unfinished"></translation>
+        <translation>Self signed door %1 (verlopen!)</translation>
     </message>
     <message>
         <source>Unverified self signed signature by %1!</source>
-        <translation type="unfinished"></translation>
+        <translation>Niet-geverifieerde 'self-signed'-signatuur door %1!</translation>
     </message>
 </context>
 <context>
@@ -11536,11 +11543,11 @@
     </message>
     <message>
         <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
-        <translation type="unfinished"></translation>
+        <translation><p><nobr>De naam of volledig pad naar de virtuelemachinemap die u op het punt staat aan te maken.</nobr></p></translation>
     </message>
     <message>
         <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
-        <translation type="unfinished"></translation>
+        <translation><p><nobr>U staat op het punt de virtuele machine aan te maken in de volgende map:</nobr><br><nobr><b>%1</b></nobr></p></translation>
     </message>
 </context>
 <context>
@@ -13363,102 +13370,102 @@
     <message>
         <source>USB</source>
         <comment>StorageBus</comment>
-        <translation type="unfinished">USB</translation>
+        <translation>USB</translation>
     </message>
     <message>
         <source>PCIe</source>
         <comment>StorageBus</comment>
-        <translation type="unfinished"></translation>
+        <translation>PCIe</translation>
     </message>
     <message>
         <source>NVMe</source>
         <comment>StorageControllerType</comment>
-        <translation type="unfinished"></translation>
+        <translation>NVMe</translation>
     </message>
     <message>
         <source>NVMe Port %1</source>
         <comment>StorageSlot</comment>
-        <translation type="unfinished"></translation>
+        <translation>NVMe Port %1</translation>
     </message>
     <message>
         <source>General</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Algemeen</translation>
+        <translation>Algemeen</translation>
     </message>
     <message>
         <source>Preview</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Preview</translation>
+        <translation>Preview</translation>
     </message>
     <message>
         <source>System</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Systeem</translation>
+        <translation>Systeem</translation>
     </message>
     <message>
         <source>Display</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Beeldscherm</translation>
+        <translation>Beeldscherm</translation>
     </message>
     <message>
         <source>Storage</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Opslag</translation>
+        <translation>Opslag</translation>
     </message>
     <message>
         <source>Audio</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Audio</translation>
+        <translation>Audio</translation>
     </message>
     <message>
         <source>Network</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Netwerk</translation>
+        <translation>Netwerk</translation>
     </message>
     <message>
         <source>Serial ports</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Seriële poorten</translation>
+        <translation>Seriële poorten</translation>
     </message>
     <message>
         <source>Parallel ports</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Parallelle porten</translation>
+        <translation>Parallelle porten</translation>
     </message>
     <message>
         <source>USB</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">USB</translation>
+        <translation>USB</translation>
     </message>
     <message>
         <source>Shared folders</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Gedeelde mappen</translation>
+        <translation>Gedeelde mappen</translation>
     </message>
     <message>
         <source>User interface</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Gebruikersinterface</translation>
+        <translation>Gebruikersinterface</translation>
     </message>
     <message>
         <source>Description</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Beschrijving</translation>
+        <translation>Beschrijving</translation>
     </message>
     <message>
         <source>Runtime attributes</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Runtime attributen</translation>
     </message>
     <message>
         <source>Storage statistics</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Opslagstatistieken</translation>
     </message>
     <message>
         <source>Network statistics</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Netwerkstatistieken</translation>
     </message>
 </context>
 <context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts
index deb0716..0d046df 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts
@@ -9750,6 +9750,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts
index 9972695..9b5980c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts
@@ -9211,6 +9211,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts
index 9bfebed..d0b569a 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts
@@ -1935,11 +1935,11 @@
     </message>
     <message>
         <source>Signature Algorithm</source>
-        <translation type="unfinished"></translation>
+        <translation>Algoritmo de Assinatura</translation>
     </message>
     <message>
         <source>X.509 Version Number</source>
-        <translation type="unfinished"></translation>
+        <translation>Versão X.509</translation>
     </message>
 </context>
 <context>
@@ -11452,15 +11452,19 @@ p, li { white-space: pre-wrap; }
     <message>
         <source>Delete</source>
         <comment>extension pack</comment>
-        <translation type="unfinished">Apagar</translation>
+        <translation>Apagar</translation>
     </message>
     <message>
         <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <translation>Você deseja apagar o arquivo baixado <nobr><b>%1</b></nobr>?</translation>
     </message>
     <message>
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <translation>Você deseja apagar a seguinte lista de arquivos <nobr><b>%1</b></nobr>?</translation>
+    </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation><p>A provável razão para este erro são permissões incorretas para o socket do daemon de IPC devido a um problema durante a instalação. Verifique as permissões de <font color=blue>'/tmp'</font> e <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
     </message>
 </context>
 <context>
@@ -17953,82 +17957,82 @@ Versão %1</translation>
     <message>
         <source>General</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Geral</translation>
+        <translation>Geral</translation>
     </message>
     <message>
         <source>Preview</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Pré-Visualização</translation>
+        <translation>Pré-Visualização</translation>
     </message>
     <message>
         <source>System</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Sistema</translation>
+        <translation>Sistema</translation>
     </message>
     <message>
         <source>Display</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Tela</translation>
     </message>
     <message>
         <source>Storage</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Armazenamento</translation>
+        <translation>Armazenamento</translation>
     </message>
     <message>
         <source>Audio</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Áudio</translation>
+        <translation>Áudio</translation>
     </message>
     <message>
         <source>Network</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Rede</translation>
+        <translation>Rede</translation>
     </message>
     <message>
         <source>Serial ports</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Portas Seriais</translation>
+        <translation>Portas Seriais</translation>
     </message>
     <message>
         <source>Parallel ports</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Portas Paralelas</translation>
+        <translation>Portas Paralelas</translation>
     </message>
     <message>
         <source>USB</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">USB</translation>
+        <translation>USB</translation>
     </message>
     <message>
         <source>Shared folders</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Pastas Compartilhadas</translation>
+        <translation>Pastas Compartilhadas</translation>
     </message>
     <message>
         <source>User interface</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Interface do Usuário</translation>
+        <translation>Interface do Usuário</translation>
     </message>
     <message>
         <source>Description</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished">Descrição</translation>
+        <translation>Descrição</translation>
     </message>
     <message>
         <source>Runtime attributes</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Atributos de Tempo de Execução</translation>
     </message>
     <message>
         <source>Storage statistics</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Estatísticas de Armazenamento</translation>
     </message>
     <message>
         <source>Network statistics</source>
         <comment>InformationElementType</comment>
-        <translation type="unfinished"></translation>
+        <translation>Estatísticas de Rede</translation>
     </message>
 </context>
 <context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts
index b431f31..4c29755 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts
@@ -9006,6 +9006,10 @@ Acest director este folosit, dacă nu este explicit specificat altfel, atunci c
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts
index 4d5f632..49ce747 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts
@@ -10757,6 +10757,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts
index 458bb1e..83319d6 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts
@@ -8972,6 +8972,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
index e7717cc..2eb3085 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
@@ -4,7 +4,7 @@
 <context>
     <name>@@@</name>
     <message>
-        <location filename="../src/globals/VBoxGlobal.cpp" line="+2064"/>
+        <location filename="../src/globals/VBoxGlobal.cpp" line="+2065"/>
         <source>English</source>
         <comment>Native language name</comment>
         <translation>Slovenščina</translation>
@@ -171,7 +171,7 @@
     <name>QIMessageBox</name>
     <message>
         <location filename="../src/extensions/QIMessageBox.cpp" line="+301"/>
-        <location filename="../src/globals/UIMessageCenter.cpp" line="+1796"/>
+        <location filename="../src/globals/UIMessageCenter.cpp" line="+1801"/>
         <location filename="../src/widgets/UIPopupPaneButtonPane.cpp" line="+180"/>
         <source>OK</source>
         <translation>V redu</translation>
@@ -6103,36 +6103,36 @@
 <context>
     <name>UIMessageCenter</name>
     <message>
-        <location filename="../src/globals/UIMessageCenter.cpp" line="-1517"/>
-        <location line="+2642"/>
+        <location filename="../src/globals/UIMessageCenter.cpp" line="-1522"/>
+        <location line="+2647"/>
         <source>VirtualBox - Information</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - podatki</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Question</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - vprašanje</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Warning</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - opozorilo</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Error</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - napaka</translation>
     </message>
     <message>
-        <location line="-2638"/>
-        <location line="+2642"/>
+        <location line="-2643"/>
+        <location line="+2647"/>
         <source>VirtualBox - Critical Error</source>
         <comment>msg box title</comment>
         <translation>VirtualBox - kritična napaka</translation>
@@ -6149,12 +6149,12 @@
         <translation>Odpiranje <tt>%1</tt> je spodeltelo. Prepričajte se, da lahko vaše namizno okolje pravilno obvlada URL te vrste.</translation>
     </message>
     <message>
-        <location line="-110"/>
+        <location line="-115"/>
         <source><p>Failed to initialize COM or to find the VirtualBox COM server. Most likely, the VirtualBox server is not running or failed to start.</p><p>The application will now terminate.</p></source>
         <translation><p>Začenjanje COM-a ali iskanje strežnika COM VirtualBox je spodletelo. Najverjetneje se VirtualBox ne izvaja ali je njegov zagon spodletel.</p><p>Program se bo sedaj končal.</p></translation>
     </message>
     <message>
-        <location line="+626"/>
+        <location line="+631"/>
         <source>Failed to set global VirtualBox properties.</source>
         <translation>Nastavitev splošnih lastnosti VirtualBoxa je spodletela.</translation>
     </message>
@@ -6498,7 +6498,7 @@
         <translation>Naslednje datoteke že obstajajo:<br /><br />%1.<br /><br />Ali jih res želite nadomestiti? Njihova nadomestitev bo prepisala njihovo vsebino.</translation>
     </message>
     <message>
-        <location line="-2074"/>
+        <location line="-2079"/>
         <source>You are running a prerelease version of VirtualBox. This version is not suitable for production use.</source>
         <translation>Izvajajte predizdajno različico VirtualBoxa. Ta različica ni primerna za proizvodno uporabo.</translation>
     </message>
@@ -6508,7 +6508,7 @@
         <translation>Gosta poizkušate izklopiti z gumbom za izklop ACPI. To trenutno ni mogoče, ker gost ne podpira zaustavtve programske opreme.</translation>
     </message>
     <message>
-        <location filename="../src/globals/UIMessageCenter.cpp" line="+1422"/>
+        <location filename="../src/globals/UIMessageCenter.cpp" line="+1427"/>
         <source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Your 64-bit guest will fail to detect a 64-bit CPU and will not be able to boot.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
         <translation><p>Strojno pospeševanje VT-x/AMD-V je bilo omogočeno, vendar ne deluje. Vaš 64-bitni gost ne bo zaznal 64-bitnega CPE-ja in se ne bo mogel zagnati.</p><p>Prepričajte se, da ste pravilno omogočili VT-x/AMD-V v BIOS-u svojega gostiteljskega računalnika.</p></translation>
     </message>
@@ -6584,7 +6584,7 @@
         <translation>Odstranjevanje datoteke je spodletelo.</translation>
     </message>
     <message>
-        <location line="-1239"/>
+        <location line="-1244"/>
         <source>You seem to have the USBFS filesystem mounted at /sys/bus/usb/drivers. We strongly recommend that you change this, as it is a severe mis-configuration of your system which could cause USB devices to fail in unexpected ways.</source>
         <translation>Videti je, da imate na /sys/bus/usb/drivers priklopljen datotečni sistem USBFS. Zelo priporočamo, da to spremenite, ker je to resna napačna nastavitev vašega sistema, ki lahko povzroči, da naprave USB spodletijo na nepričakovane načine.</translation>
     </message>
@@ -6594,7 +6594,7 @@
         <translation>Izvajate PREIZKUSNO izgradnjo VirtualBoxa. Ta različica ni primerna za proizvodno uporabo.</translation>
     </message>
     <message>
-        <location line="+447"/>
+        <location line="+452"/>
         <location line="+9"/>
         <source>Restore</source>
         <translation>Obnovi</translation>
@@ -6919,12 +6919,12 @@
         <translation><p>Nameščeno imate različico %1 <b><nobr>%2</nobr></b>.</p><p>Prejmite in namestite različico %3 tega paketa razširitev od Oracla!</p></translation>
     </message>
     <message>
-        <location line="-1701"/>
+        <location line="-1706"/>
         <source><p>Failed to initialize COM because the VirtualBox global configuration directory <b><nobr>%1</nobr></b> is not accessible. Please check the permissions of this directory and of its parent directory.</p><p>The application will now terminate.</p></source>
         <translation><p>Začenjanje COM-a je spodletelo, ker mapa splošnih nastavitev VirtualBoxa <b><nobr>%1</nobr></b> ni na voljo. Preverite dovoljenja te in njene nadrejene mape.</p><p>Program se bo sedaj končal.</p></translation>
     </message>
     <message>
-        <location line="+200"/>
+        <location line="+205"/>
         <source><p>You are about to remove following virtual machine items from the machine list:</p><p><b>%1</b></p><p>Do you wish to proceed?</p></source>
         <translation><p>Ste pred odstranitvijo naslednjih predmetov navideznega računalnika s seznama računalnikov:</p><p><b>%1</b></p><p>Ali želite nadaljevati?</p></translation>
     </message>
@@ -7031,12 +7031,17 @@
         <translation>Spremeni omrežne nastavitve</translation>
     </message>
     <message>
-        <location line="-1467"/>
+        <location line="-1472"/>
         <source><p>Cannot start the VirtualBox Manager due to local restrictions.</p><p>The application will now terminate.</p></source>
         <translation><p>Upravljalnika VirtualBoxa ni mogoče zagnati zaradi krajevnih omejitev.</p><p>Program se bo sedaj zaprl.</p></translation>
     </message>
     <message>
-        <location line="+57"/>
+        <location line="+52"/>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+10"/>
         <source><p>Could not find a language file for the language <b>%1</b> in the directory <b><nobr>%2</nobr></b>.</p><p>The language will be temporarily reset to the system default language. Please go to the <b>Preferences</b> window which you can open from the <b>File</b> menu of the VirtualBox Manager window, and select one of the existing languages on the <b>Language</b> page.</p></source>
         <translation><p>Datoteke jezika <b>%1</b> v mapi <b><nobr>%2</nobr></b> ni bilo mogoče najti.</p><p>Jezik bo začasno ponastavljen na sistemsko privzetega. Pojdite v okno <b>Možnosti</b>, ki ga lahko odprete iz menija<b>Datoteka</b> okna Upravljalnika VirtualBoxa in izbiro enega od obstoječih jezikov na strani <b>Jeziki</b>.</p></translation>
     </message>
@@ -7298,12 +7303,12 @@
         <translation>Trenutna pravila posredovanja vrat niso veljavna. Nekaj pravil ima enaka vrata gostitelja in naslove IP v sporu.</translation>
     </message>
     <message>
-        <location line="-771"/>
+        <location line="-776"/>
         <source><p>Failed to create the VirtualBoxClient COM object.</p><p>The application will now terminate.</p></source>
         <translation><p>Ustvarjanje predmeta COM odjemalca VirtualBox je spodletelo.</p><p>Program se bo sedaj zaprl.</p></translation>
     </message>
     <message>
-        <location line="+109"/>
+        <location line="+114"/>
         <source>Failed to set the global VirtualBox extra data for key <i>%1</i> to value <i>{%2}</i>.</source>
         <translation>Nastavitev splošnih dodatnih podatkov VirtualBoxa za ključ <i>%1</i> na vrednost <i>{%2}</i> je spodletela.</translation>
     </message>
@@ -7471,7 +7476,7 @@
         <translation>Trenutna pravila posredovanja vrat niso veljavna. Nobena vrednost naslovov gosta ne sme biti prazna.</translation>
     </message>
     <message>
-        <location line="-747"/>
+        <location line="-753"/>
         <source><p>Failed to acquire the VirtualBox COM object.</p><p>The application will now terminate.</p></source>
         <translation><p>Pridobivanje predmeta VirtualBox COM je spodletelo.</p><p>Program se bo sedaj zaprl.</p></translation>
     </message>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts
index 19e70d5..31a38f9 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts
@@ -9943,6 +9943,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts
index 34e91c7..dba2892 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts
@@ -10982,6 +10982,10 @@ serial ports</comment>
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts
index 145311b..6e5d47e 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts
@@ -109,7 +109,7 @@
     </message>
     <message>
         <source>Make sure the kernel module has been loaded successfully.</source>
-        <translation>Kernel modülünün başarılı olarak yüklendiğinden emin olun.</translation>
+        <translation>Çekirdek parçasının başarılı olarak yüklendiğinden emin olun.</translation>
     </message>
     <message>
         <source>VirtualBox - Runtime Error</source>
@@ -117,7 +117,7 @@
     </message>
     <message>
         <source><b>Cannot access the kernel driver!</b><br/><br/></source>
-        <translation><b>Kernel sürücüsüne erişilemiyor!</b><br/><br/></translation>
+        <translation><b>Çekirdek sürücüsüne erişilemiyor!</b><br/><br/></translation>
     </message>
     <message>
         <source>Unknown error %2 during initialization of the Runtime</source>
@@ -125,23 +125,23 @@
     </message>
     <message>
         <source>Kernel driver not accessible</source>
-        <translation>Kernel sürücüsü erişilebilir değil</translation>
+        <translation>Çekirdek sürücüsü erişilebilir değil</translation>
     </message>
     <message>
         <source>The VirtualBox kernel modules do not match this version of VirtualBox. The installation of VirtualBox was apparently not successful. Please try completely uninstalling and reinstalling VirtualBox.</source>
-        <translation>VirtualBox kernel modülleri VirtualBox'ın bu sürümüyle uyuşmuyor. VirtualBox'ın kurulumu görünüşe göre başarılı olmadı. Lütfen VirtualBox'ı tamamen kaldırmayı ve yeniden yüklemeyi deneyin.</translation>
+        <translation>VirtualBox çekirdek parçaları VirtualBox'ın bu sürümüyle uyuşmuyor. VirtualBox'ın kurulumu görünüşe göre başarılı olmadı. Lütfen VirtualBox'ı tamamen kaldırmayı ve yeniden yüklemeyi deneyin.</translation>
     </message>
     <message>
         <source>The VirtualBox kernel modules do not match this version of VirtualBox. The installation of VirtualBox was apparently not successful. Executing<br/><br/>  <font color=blue>'/sbin/rcvboxdrv setup'</font><br/><br/>may correct this. Make sure that you do not mix the OSE version and the PUEL version of VirtualBox.</source>
-        <translation type="vanished">VirtualBox kernel modülleri VirtualBox'ın bu sürümüyle uyuşmuyor. VirtualBox'ın kurulumu görünüşe göre başarılı olmadı. <br/><br/>  <font color=blue>'/sbin/rcvboxdrv setup'</font><br/><br/> dosyasını çalıştırmak bunu düzeltebilir. VirtualBox'ın OSE ve PUEL sürümlerini karıştırmadığınızdan emin olun.</translation>
+        <translation type="vanished">VirtualBox çekirdek parçaları VirtualBox'ın bu sürümüyle uyuşmuyor. VirtualBox'ın kurulumu görünüşe göre başarılı olmadı. <br/><br/>  <font color=blue>'/sbin/rcvboxdrv setup'</font><br/><br/> dosyasını çalıştırmak bunu düzeltebilir. VirtualBox'ın OSE ve PUEL sürümlerini karıştırmadığınızdan emin olun.</translation>
     </message>
     <message>
         <source>This error means that the kernel driver was either not able to allocate enough memory or that some mapping operation failed.</source>
-        <translation>Bu hata kernel sürücüsünün ya yeterli bellek ayıramadığını ya da bazı planlama işleminin başarısız olduğu anlamına gelir.</translation>
+        <translation>Bu hata çekirdek sürücüsünün ya yeterli bellek ayıramadığını ya da bazı planlama işleminin başarısız olduğu anlamına gelir.</translation>
     </message>
     <message>
         <source>The VirtualBox Linux kernel driver (vboxdrv) is either not loaded or there is a permission problem with /dev/vboxdrv. Please reinstall the kernel module by executing<br/><br/>  <font color=blue>'/sbin/rcvboxdrv setup'</font><br/><br/>as root. If it is available in your distribution, you should install the DKMS package first. This package keeps track of Linux kernel changes and recompiles the vboxdrv kernel module if necessary. [...]
-        <translation type="vanished">VirtualBox Linux kernel sürücüsü (vboxdrv) ya yüklenemiyor ya da /dev/vboxdrv ile ilgili izin sorunu var. Lütfen root olarak <br/><br/>  <font color=blue>'/sbin/rcvboxdrv setup'</font><br/><br/> dosyasını çalıştırarak kernel modülünü yeniden yükleyin. Eğer dağıtımınızda mevcutsa, önce DKMS paketini yüklemelisiniz. Bu paket Linux kernel değişikliklerinin izini tutar ve eğer gerekirse vboxdrv kernel modülünü [...]
+        <translation type="vanished">VirtualBox Linux çekirdek sürücüsü (vboxdrv) ya yüklenemiyor ya da /dev/vboxdrv ile ilgili izin sorunu var. Lütfen kök olarak <br/><br/>  <font color=blue>'/sbin/rcvboxdrv setup'</font><br/><br/> dosyasını çalıştırarak çekirdek parçasını yeniden yükleyin. Eğer dağıtımınızda mevcutsa, önce DKMS paketini yüklemelisiniz. Bu paket Linux çekirdek değişikliklerinin izini tutar ve eğer gerekirse vboxdrv çekirdek  [...]
     </message>
     <message>
         <source>Frame Size: %1x%2, Frame Rate: %3fps, Bit Rate: %4kbps</source>
@@ -149,11 +149,11 @@
     </message>
     <message>
         <source>The VirtualBox Linux kernel driver (vboxdrv) is either not loaded or there is a permission problem with /dev/vboxdrv. Please reinstall the kernel module by executing<br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/>as root.</source>
-        <translation>VirtualBox Linux kernel sürücüsü (vboxdrv) ya yüklenemiyor ya da /dev/vboxdrv ile ilgili izin sorunu var. Lütfen root olarak <br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/> dosyasını çalıştırarak kernel modülünü yeniden yükleyin.</translation>
+        <translation>VirtualBox Linux çekirdek sürücüsü (vboxdrv) ya yüklenemiyor ya da /dev/vboxdrv ile ilgili izin sorunu var. Lütfen kök olarak <br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/> dosyasını çalıştırarak çekirdek parçasını yeniden yükleyin.</translation>
     </message>
     <message>
         <source>The VirtualBox kernel modules do not match this version of VirtualBox. The installation of VirtualBox was apparently not successful. Executing<br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/>may correct this. Make sure that you do not mix the OSE version and the PUEL version of VirtualBox.</source>
-        <translation>VirtualBox kernel modülleri VirtualBox'ın bu sürümüyle uyuşmuyor. VirtualBox'ın kurulumu görünüşe göre başarılı olmadı. <br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/> dosyasını çalıştırmak bunu düzeltebilir. VirtualBox'ın OSE ve PUEL sürümlerini karıştırmadığınızdan emin olun.</translation>
+        <translation>VirtualBox çekirdek parçaları VirtualBox'ın bu sürümüyle uyuşmuyor. VirtualBox'ın kurulumu görünüşe göre başarılı olmadı. <br/><br/>  <font color=blue>'/sbin/vboxconfig'</font><br/><br/> dosyasını çalıştırmak bunu düzeltebilir. VirtualBox'ın OSE ve PUEL sürümlerini karıştırmadığınızdan emin olun.</translation>
     </message>
 </context>
 <context>
@@ -320,11 +320,11 @@
     </message>
     <message>
         <source>Auto-resize &Guest Display</source>
-        <translation>Misafir E&kranını otomatik yeniden boyutlandır</translation>
+        <translation>Misafir E&kranını kendiliğinden yeniden boyutlandır</translation>
     </message>
     <message>
         <source>Automatically resize the guest display when the window is resized (requires Guest Additions)</source>
-        <translation type="obsolete">Pencere yeniden boyutlandırıldığında misafir ekranını otomatik olarak yeniden boyutlandır (Misafir Eklentilerini gerektirir)</translation>
+        <translation type="obsolete">Pencere yeniden boyutlandırıldığında misafir ekranını kendiliğinden yeniden boyutlandır (Misafir Eklentilerini gerektirir)</translation>
     </message>
     <message>
         <source>&Adjust Window Size</source>
@@ -588,7 +588,7 @@
     </message>
     <message>
         <source>Check for a new VirtualBox version</source>
-        <translation>Yeni VirtualBox sürümünü kontrol et</translation>
+        <translation>Yeni VirtualBox sürümünü denetle</translation>
     </message>
     <message>
         <source>&About VirtualBox...</source>
@@ -634,19 +634,19 @@
     </message>
     <message>
         <source>&Import Appliance...</source>
-        <translation>Cihazı İç&e Aktar...</translation>
+        <translation>Aygıtı İç&e Aktar...</translation>
     </message>
     <message>
         <source>Import an appliance into VirtualBox</source>
-        <translation>VirtualBox içerisine bir cihaz aktar</translation>
+        <translation>VirtualBox içerisine bir aygıt aktar</translation>
     </message>
     <message>
         <source>&Export Appliance...</source>
-        <translation>Cihazı &Dışa Aktar...</translation>
+        <translation>Aygıtı &Dışa Aktar...</translation>
     </message>
     <message>
         <source>Export one or more VirtualBox virtual machines as an appliance</source>
-        <translation>Bir ya da daha fazla VirtualBox sanal makinesini bir cihaz olarak dışa aktar</translation>
+        <translation>Bir ya da daha fazla VirtualBox sanal makinesini bir aygıt olarak dışa aktar</translation>
     </message>
     <message>
         <source>&Preferences...</source>
@@ -731,7 +731,7 @@
     </message>
     <message>
         <source>Add a new group based on the items selected</source>
-        <translation type="obsolete">Seçilen öğelere dayalı yeni bir grup ekle</translation>
+        <translation type="obsolete">Seçilen ögelere dayalı yeni bir grup ekle</translation>
     </message>
     <message>
         <source>Cl&one...</source>
@@ -775,7 +775,7 @@
     </message>
     <message>
         <source>C&heck for Updates...</source>
-        <translation>&Güncellemeleri Kontrol Et...</translation>
+        <translation>&Güncellemeleri Denetle...</translation>
     </message>
     <message>
         <source>Rena&me Group...</source>
@@ -783,7 +783,7 @@
     </message>
     <message>
         <source>Sort the items of the selected virtual machine group alphabetically</source>
-        <translation type="obsolete">Seçilen sanal makine grubunun öğelerini alfabetik olarak sırala</translation>
+        <translation type="obsolete">Seçilen sanal makine grubunun ögelerini alfabetik olarak sırala</translation>
     </message>
     <message>
         <source>Remove the selected virtual machines</source>
@@ -867,7 +867,7 @@
     </message>
     <message>
         <source>Ungroup items of the selected virtual machine group</source>
-        <translation type="obsolete">Seçilen sanal makine grubunun öğelerinin grublamasını kaldır</translation>
+        <translation type="obsolete">Seçilen sanal makine grubunun ögelerinin grublamasını kaldır</translation>
     </message>
     <message>
         <source>Sort</source>
@@ -1145,7 +1145,7 @@
     </message>
     <message>
         <source>Minimize active window</source>
-        <translation>Aktif pencereyi simge durumuna küçült</translation>
+        <translation>Etkin pencereyi simge durumuna küçült</translation>
     </message>
     <message>
         <source>Display the Network Operations Manager window</source>
@@ -1190,7 +1190,7 @@
     </message>
     <message>
         <source>Automatically resize the guest display when the window is resized</source>
-        <translation>Pencere yeniden boyutlandırıldığında misafir ekranını otomatik olarak yeniden boyutlandır</translation>
+        <translation>Pencere yeniden boyutlandırıldığında misafir ekranını kendiliğinden yeniden boyutlandır</translation>
     </message>
     <message>
         <source>Take guest display screenshot</source>
@@ -1330,7 +1330,7 @@
     </message>
     <message>
         <source>Ungroup items of selected virtual machine group</source>
-        <translation>Seçilen sanal makine grubunun öğelerinin grublamasını kaldır</translation>
+        <translation>Seçilen sanal makine grubunun ögelerinin grublamasını kaldır</translation>
     </message>
     <message>
         <source>&Sort</source>
@@ -1338,7 +1338,7 @@
     </message>
     <message>
         <source>Sort items of selected virtual machine group alphabetically</source>
-        <translation>Seçilen sanal makine grubunun öğelerini alfabetik olarak sırala</translation>
+        <translation>Seçilen sanal makine grubunun ögelerini alfabetik olarak sırala</translation>
     </message>
     <message>
         <source>Add new group based on selected virtual machines</source>
@@ -1638,7 +1638,7 @@
     </message>
     <message>
         <source>Unknown Hardware Item</source>
-        <translation>Bilinmeyen Donanım Öğesi</translation>
+        <translation>Bilinmeyen Donanım Ögesi</translation>
     </message>
     <message>
         <source>MB</source>
@@ -1699,11 +1699,11 @@
     <name>UIApplianceImportEditorWidget</name>
     <message>
         <source>Importing Appliance ...</source>
-        <translation>Cihaz içe aktarılıyor ...</translation>
+        <translation>Aygıt içe aktarılıyor ...</translation>
     </message>
     <message>
         <source>Reading Appliance ...</source>
-        <translation>Cihaz okunuyor ...</translation>
+        <translation>Aygıt okunuyor ...</translation>
     </message>
 </context>
 <context>
@@ -1714,11 +1714,11 @@
     </message>
     <message>
         <source><b>The appliance is signed by an unverified self signed certificate issued by '%1'. We recommend to only proceed with the importing if you are sure you should trust this entity.</b></source>
-        <translation><b>Cihaz doğrulanamayan bir kendinden imzalı sertifika vereni '%1' tarafından imzalı. Sadece eğer bu varlığa güvenmeniz gerektiğinden eminseniz içe aktararak devam etmenizi öneririz.</b></translation>
+        <translation><b>Aygıt doğrulanamayan bir kendinden imzalı sertifika vereni '%1' tarafından imzalı. Yalnızca eğer bu varlığa güvenmeniz gerektiğinden eminseniz içe aktararak devam etmenizi öneririz.</b></translation>
     </message>
     <message>
         <source><b>The appliance is signed by an unverified certificate issued to '%1'. We recommend to only proceed with the importing if you are sure you should trust this entity.</b></source>
-        <translation><b>Cihaz doğrulanamayan bir sertifika veren '%1' tarafından imzalı. Sadece eğer bu varlığa güvenmeniz gerektiğinden eminseniz içe aktararak devam etmenizi öneririz.</b></translation>
+        <translation><b>Aygıt doğrulanamayan bir sertifika veren '%1' tarafından imzalı. Yalnızca eğer bu varlığa güvenmeniz gerektiğinden eminseniz içe aktararak devam etmenizi öneririz.</b></translation>
     </message>
     <message>
         <source>Issuer:               %1</source>
@@ -1993,7 +1993,7 @@
     <message>
         <source>Host-only adapter, '%1'</source>
         <comment>details report (network)</comment>
-        <translation type="obsolete">Sadece-anamakine bağdaştırıcısı, '%1'</translation>
+        <translation type="obsolete">Yalnızca-anamakine bağdaştırıcısı, '%1'</translation>
     </message>
     <message>
         <source>Generic driver, '%1'</source>
@@ -2215,7 +2215,7 @@
     </message>
     <message>
         <source>The selected virtual machine is <i>inaccessible</i>. Please inspect the error message shown below and press the <b>Refresh</b> button if you want to repeat the accessibility check:</source>
-        <translation>Seçilen sanal makineye <i>erişilemez</i>. Lütfen aşağıdaki hata iletisine bakın ve <b>Yenile</b> düğmesine basarak erişebilmenize yarayacak ilgili iletileri kontro edin:</translation>
+        <translation>Seçilen sanal makineye <i>erişilemez</i>. Lütfen aşağıdaki hata iletisine bakın ve <b>Yenile</b> düğmesine basarak erişebilmenize yarayacak ilgili iletileri denetleyin:</translation>
     </message>
     <message>
         <source>General</source>
@@ -2474,7 +2474,7 @@
     </message>
     <message>
         <source>The actual default path value will be displayed after accepting the changes and opening this window again.</source>
-        <translation>Gerçek varsayılan yol değeri, değişiklikler kabul edildikten ve bu pencere tekrar açıldıktan sonra görüntülenecektir.</translation>
+        <translation>Gerçek varsayılan yol değeri, değişiklikler kabul edildikten ve bu pencere yeniden açıldıktan sonra görüntülenecektir.</translation>
     </message>
     <message>
         <source><not selected></source>
@@ -2553,7 +2553,7 @@
     </message>
     <message>
         <source><p>If the above is correct, press the <b>Finish</b> button. Once you press it, the selected media will be temporarily mounted on the virtual machine and the machine will start execution.</p><p>Please note that when you close the virtual machine, the specified media will be automatically unmounted and the boot device will be set back to the first hard disk.</p><p>Depending on the type of the setup program, you may need to manually  [...]
-        <translation type="obsolete"><p>Eğer yukarıdakiler doğru ise,<b>Bitir</b> düğmesine basın. Düğmeye bastığınızda, seçilen ortam sanal makineye bağlanacak ve makine çalıştırılmaya başlanacak.</p><p>Sanal makineyi kapattığınızda belirtilen ortamın otomatik olarak ayrılacağını ve başlangıç aygıtının yeniden sabit disk olarak ayarlanacağını unutmayın.</p><p>Kur uygulamasına bağlı olarak değişmekle birlikte, kur işleminin yeniden başlamasını en [...]
+        <translation type="obsolete"><p>Eğer yukarıdakiler doğru ise,<b>Bitir</b> düğmesine basın. Düğmeye bastığınızda, seçilen ortam sanal makineye bağlanacak ve makine çalıştırılmaya başlanacak.</p><p>Sanal makineyi kapattığınızda belirtilen ortamın kendiliğinden ayrılacağını ve başlangıç aygıtının yeniden sabit disk olarak ayarlanacağını unutmayın.</p><p>Kur uygulamasına bağlı olarak değişmekle birlikte, kur işleminin yeniden başlamasını enge [...]
     </message>
     <message>
         <source>Summary</source>
@@ -2664,7 +2664,7 @@
     </message>
     <message>
         <source><p>If the above is correct, press the <b>Finish</b> button. Once you press it, the selected media will be temporarily mounted on the virtual machine and the machine will start execution.</p><p>Please note that when you close the virtual machine, the specified media will be automatically unmounted and the boot device will be set back to the first hard disk.</p><p>Depending on the type of the setup program, you may need to manually  [...]
-        <translation type="obsolete"><p>Eğer yukarıdakiler doğru ise,<b>Bitir</b> düğmesine basın. Düğmeye bastığınızda, seçilen ortam sanal makineye bağlanacak ve makine çalıştırılmaya başlanacak.</p><p>Sanal makineyi kapattığınızda belirtilen ortamın otomatik olarak ayrılacağını ve başlangıç aygıtının yeniden sabit disk olarak ayarlanacağını unutmayın.</p><p>Kur uygulamasına bağlı olarak değişmekle birlikte, kur işleminin yeniden başlamasını en [...]
+        <translation type="obsolete"><p>Eğer yukarıdakiler doğru ise,<b>Bitir</b> düğmesine basın. Düğmeye bastığınızda, seçilen ortam sanal makineye bağlanacak ve makine çalıştırılmaya başlanacak.</p><p>Sanal makineyi kapattığınızda belirtilen ortamın kendiliğinden ayrılacağını ve başlangıç aygıtının yeniden sabit disk olarak ayarlanacağını unutmayın.</p><p>Kur uygulamasına bağlı olarak değişmekle birlikte, kur işleminin yeniden başlamasını enge [...]
     </message>
     <message>
         <source><p>If the above is correct, press the <b>Finish</b> button. Once you press it, the selected media will be mounted on the virtual machine and the machine will start execution.</p></source>
@@ -2961,7 +2961,7 @@
     <message>
         <source>Host-only Adapter, '%1'</source>
         <comment>details (network)</comment>
-        <translation>Sadece-Anamakine Bağdaştırıcısı, '%1'</translation>
+        <translation>Yalnızca-Anamakine Bağdaştırıcısı, '%1'</translation>
     </message>
     <message>
         <source>Generic Driver, '%1'</source>
@@ -3332,11 +3332,11 @@
     <message>
         <source>Automatic</source>
         <comment>Maximum Guest Screen Size</comment>
-        <translation>Otomatik</translation>
+        <translation>Kendiliğinden</translation>
     </message>
     <message>
         <source>Suggest a reasonable maximum screen size to the guest. The guest will only see this suggestion when guest additions are installed.</source>
-        <translation>Misafire makul en fazla ekran boyutunu önerir. Misafir eklentileri yüklendiğinde misafir sadece bu öneriyi görecektir.</translation>
+        <translation>Misafire makul en fazla ekran boyutunu önerir. Misafir eklentileri yüklendiğinde misafir yalnızca bu öneriyi görecektir.</translation>
     </message>
     <message>
         <source>None</source>
@@ -3354,7 +3354,7 @@
     </message>
     <message>
         <source>Suggest a maximum screen size to the guest. The guest will only see this suggestion when guest additions are installed.</source>
-        <translation>Misafire en fazla ekran boyutunu önerir. Misafir eklentileri yüklendiğinde misafir sadece bu öneriyi görecektir.</translation>
+        <translation>Misafire en fazla ekran boyutunu önerir. Misafir eklentileri yüklendiğinde misafir yalnızca bu öneriyi görecektir.</translation>
     </message>
     <message>
         <source>Machine Windows:</source>
@@ -3393,7 +3393,7 @@
     </message>
     <message>
         <source>Active</source>
-        <translation>Aktif</translation>
+        <translation>Etkin</translation>
     </message>
     <message>
         <source>Name</source>
@@ -3484,7 +3484,7 @@
     </message>
     <message>
         <source>&Auto show Dock and Menubar in fullscreen</source>
-        <translation type="obsolete">Tam ekranda Yapışık Alan ve Menü Çubuğunu &otomatik göster</translation>
+        <translation type="obsolete">Tam ekranda Yapışık Alan ve Menü Çubuğunu &kendiliğinden göster</translation>
     </message>
     <message>
         <source>When checked, the host screen saver will be disabled whenever a virtual machine is running.</source>
@@ -3500,7 +3500,7 @@
     </message>
     <message>
         <source>Auto-Show in Fullscreen</source>
-        <translation type="obsolete">Tam Ekranda Otomatik Göster</translation>
+        <translation type="obsolete">Tam Ekranda Kendiliğinden Göster</translation>
     </message>
     <message>
         <source>When checked, the host dock and menu bar will be shown when the virtual machine is in fullscreen mode.</source>
@@ -3539,11 +3539,11 @@
     </message>
     <message>
         <source>When checked, the keyboard is automatically captured every time the VM window is activated. When the keyboard is captured, all keystrokes (including system ones like Alt-Tab) are directed to the VM.</source>
-        <translation>İşaretlendiğinde, VM penceresinin etkinleştirildiği her defasında klavye otomatik olarak yakalanır. Klavye yakalandığında, tüm tuşa basmalar (Alt-Tab gibi sistem için olanlar dahil) VM'e yönlendirilir.</translation>
+        <translation>İşaretlendiğinde, VM penceresinin etkinleştirildiği her defasında klavye kendiliğinden yakalanır. Klavye yakalandığında, tüm tuşa basmalar (Alt-Tab gibi sistem için olanlar dahil) VM'e yönlendirilir.</translation>
     </message>
     <message>
         <source>&Auto Capture Keyboard</source>
-        <translation>&Klavyeyi Otomatik Yakala</translation>
+        <translation>&Klavyeyi Kendiliğinden Yakala</translation>
     </message>
     <message>
         <source>Reset host combination</source>
@@ -3559,7 +3559,7 @@
     </message>
     <message>
         <source>Some items have the same shortcuts assigned.</source>
-        <translation>Bazı öğeler atanmış aynı kısayollara sahip.</translation>
+        <translation>Bazı ögeler atanmış aynı kısayollara sahip.</translation>
     </message>
     <message>
         <source>&VirtualBox Manager</source>
@@ -3682,7 +3682,7 @@
     <message>
         <source>Automatically configured</source>
         <comment>interface</comment>
-        <translation>Otomatik olarak yapılandırılmış</translation>
+        <translation>Kendiliğinden yapılandırılmış</translation>
     </message>
     <message>
         <source>Manually configured</source>
@@ -3757,15 +3757,15 @@
     </message>
     <message>
         <source>&Add host-only network</source>
-        <translation type="obsolete">Sadece-anamakine ağı &ekle</translation>
+        <translation type="obsolete">Yalnızca-anamakine ağı &ekle</translation>
     </message>
     <message>
         <source>&Remove host-only network</source>
-        <translation type="obsolete">Sadece-anamakine ağını &kaldır</translation>
+        <translation type="obsolete">Yalnızca-anamakine ağını &kaldır</translation>
     </message>
     <message>
         <source>&Edit host-only network</source>
-        <translation type="obsolete">Sadece-anamakine ağını &düzenle</translation>
+        <translation type="obsolete">Yalnızca-anamakine ağını &düzenle</translation>
     </message>
     <message>
         <source>&Host-only Networks:</source>
@@ -3773,7 +3773,7 @@
     </message>
     <message>
         <source>Lists all available host-only networks.</source>
-        <translation>Tüm kullanılabilir sadece-anamakine ağlarını listeler.</translation>
+        <translation>Tüm kullanılabilir yalnızca-anamakine ağlarını listeler.</translation>
     </message>
     <message>
         <source>Name</source>
@@ -3894,7 +3894,7 @@
     <message>
         <source>Active</source>
         <comment>NAT network</comment>
-        <translation>Aktif</translation>
+        <translation>Etkin</translation>
     </message>
     <message>
         <source>&Add NAT network</source>
@@ -3934,27 +3934,27 @@
     </message>
     <message>
         <source>Add Host-only Network</source>
-        <translation>Sadece-anamakine Ağı Ekle</translation>
+        <translation>Yalnızca-anamakine Ağı Ekle</translation>
     </message>
     <message>
         <source>Remove Host-only Network</source>
-        <translation>Sadece-anamakine Ağını Kaldır</translation>
+        <translation>Yalnızca-anamakine Ağını Kaldır</translation>
     </message>
     <message>
         <source>Edit Host-only Network</source>
-        <translation>Sadece-anamakine Ağını Düzenle</translation>
+        <translation>Yalnızca-anamakine Ağını Düzenle</translation>
     </message>
     <message>
         <source>Adds new host-only network.</source>
-        <translation>Yeni sadece-anamakine ağı ekler.</translation>
+        <translation>Yeni yalnızca-anamakine ağı ekler.</translation>
     </message>
     <message>
         <source>Removes selected host-only network.</source>
-        <translation>Seçilen sadece-anamakine ağını kaldırır.</translation>
+        <translation>Seçilen yalnızca-anamakine ağını kaldırır.</translation>
     </message>
     <message>
         <source>Edits selected host-only network.</source>
-        <translation>Seçilen sadece-anamakine ağını düzenler.</translation>
+        <translation>Seçilen yalnızca-anamakine ağını düzenler.</translation>
     </message>
     <message>
         <source>Host interface <b>%1</b> does not currently have a valid IPv6 network mask prefix length.</source>
@@ -3965,7 +3965,7 @@
     <name>UIGlobalSettingsNetworkDetails</name>
     <message>
         <source>Host-only Network Details</source>
-        <translation type="obsolete">Sadece-Anamakine Ağı Ayrıntıları</translation>
+        <translation type="obsolete">Yalnızca-Anamakine Ağı Ayrıntıları</translation>
     </message>
     <message>
         <source>&Adapter</source>
@@ -3977,7 +3977,7 @@
     </message>
     <message>
         <source>Use manual configuration for this host-only network adapter.</source>
-        <translation type="obsolete">Bu sadece-anamakine ağı bağdaştırıcısı için elle yapılandırma kullan.</translation>
+        <translation type="obsolete">Bu yalnızca-anamakine ağı bağdaştırıcısı için elle yapılandırma kullan.</translation>
     </message>
     <message>
         <source>&IPv4 Address:</source>
@@ -4029,7 +4029,7 @@
     </message>
     <message>
         <source>Holds the address of the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation type="obsolete">Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun adresini gösterir.</translation>
+        <translation type="obsolete">Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun adresini gösterir.</translation>
     </message>
     <message>
         <source>Server &Mask:</source>
@@ -4037,7 +4037,7 @@
     </message>
     <message>
         <source>Holds the network mask of the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation type="obsolete">Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun ağ maskesini gösterir.</translation>
+        <translation type="obsolete">Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun ağ maskesini gösterir.</translation>
     </message>
     <message>
         <source>&Lower Address Bound:</source>
@@ -4045,7 +4045,7 @@
     </message>
     <message>
         <source>Holds the lower address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation type="obsolete">Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş alt adres sınırını gösterir.</translation>
+        <translation type="obsolete">Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş alt adres sınırını gösterir.</translation>
     </message>
     <message>
         <source>&Upper Address Bound:</source>
@@ -4053,14 +4053,14 @@
     </message>
     <message>
         <source>Holds the upper address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation type="obsolete">Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş üst adres sınırını gösterir.</translation>
+        <translation type="obsolete">Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş üst adres sınırını gösterir.</translation>
     </message>
 </context>
 <context>
     <name>UIGlobalSettingsNetworkDetailsHost</name>
     <message>
         <source>Host-only Network Details</source>
-        <translation>Sadece-Anamakine Ağı Ayrıntıları</translation>
+        <translation>Yalnızca-Anamakine Ağı Ayrıntıları</translation>
     </message>
     <message>
         <source>&Adapter</source>
@@ -4072,7 +4072,7 @@
     </message>
     <message>
         <source>Use manual configuration for this host-only network adapter.</source>
-        <translation type="obsolete">Bu sadece-anamakine ağı bağdaştırıcısı için elle yapılandırma kullan.</translation>
+        <translation type="obsolete">Bu yalnızca-anamakine ağı bağdaştırıcısı için elle yapılandırma kullan.</translation>
     </message>
     <message>
         <source>&IPv4 Address:</source>
@@ -4124,7 +4124,7 @@
     </message>
     <message>
         <source>Holds the address of the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation>Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun adresini tutar.</translation>
+        <translation>Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun adresini tutar.</translation>
     </message>
     <message>
         <source>Server &Mask:</source>
@@ -4132,7 +4132,7 @@
     </message>
     <message>
         <source>Holds the network mask of the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation>Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun ağ maskesini tutar.</translation>
+        <translation>Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusunun ağ maskesini tutar.</translation>
     </message>
     <message>
         <source>&Lower Address Bound:</source>
@@ -4140,7 +4140,7 @@
     </message>
     <message>
         <source>Holds the lower address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation>Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş alt adres sınırını tutar.</translation>
+        <translation>Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş alt adres sınırını tutar.</translation>
     </message>
     <message>
         <source>&Upper Address Bound:</source>
@@ -4148,7 +4148,7 @@
     </message>
     <message>
         <source>Holds the upper address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
-        <translation>Bu sadece-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş üst adres sınırını tutar.</translation>
+        <translation>Bu yalnızca-anamakine bağdaştırıcısı ile ilişkilendirilmiş ağa hizmet eden DHCP sunucusu tarafından sunulmuş üst adres sınırını tutar.</translation>
     </message>
     <message>
         <source>When checked, manual configuration will be used for this network adapter.</source>
@@ -4313,31 +4313,31 @@
     </message>
     <message>
         <source>No proxy host is currently specified.</source>
-        <translation>Şu anda hiç proksi anamakinesi belirtilmedi.</translation>
+        <translation>Şu anda hiç vekil anamakinesi belirtilmedi.</translation>
     </message>
     <message>
         <source>No proxy port is currently specified.</source>
-        <translation>Şu anda hiç proksi bağlantı noktası belirtilmedi.</translation>
+        <translation>Şu anda hiç vekil bağlantı noktası belirtilmedi.</translation>
     </message>
     <message>
         <source>Holds the proxy host.</source>
-        <translation>Proksi anamakinesini tutar.</translation>
+        <translation>Vekil anamakinesini tutar.</translation>
     </message>
     <message>
         <source>Holds the proxy port.</source>
-        <translation>Proksi bağlantı noktasını tutar.</translation>
+        <translation>Vekil bağlantı noktasını tutar.</translation>
     </message>
     <message>
         <source>When chosen, VirtualBox will try to auto-detect host proxy settings for tasks like downloading Guest Additions from the network or checking for updates.</source>
-        <translation>Seçildiğinde, VirtualBox ağdan Misafir Eklentilerini indirme ya da güncellemeleri kontrol etme gibi görevler için anamakine proksi ayarlarını otomatik algılamaya çalışacak.</translation>
+        <translation>Seçildiğinde, VirtualBox ağdan Misafir Eklentilerini indirme ya da güncellemeleri denetleme gibi görevler için anamakine vekil ayarlarını kendiliğinden algılamaya çalışacak.</translation>
     </message>
     <message>
         <source>&Auto-detect Host Proxy Settings</source>
-        <translation>Anamakine Proksi Ayarlarını Otomatik &Algıla</translation>
+        <translation>Anamakine Vekil Ayarlarını Kendiliğinden &Algıla</translation>
     </message>
     <message>
         <source>When chosen, VirtualBox will use direct Internet connection for tasks like downloading Guest Additions from the network or checking for updates.</source>
-        <translation>Seçildiğinde, VirtualBox ağdan Misafir Eklentilerini indirme ya da güncellemeleri kontrol etme gibi görevler için doğrudan Internet bağlantısı kullanacak.</translation>
+        <translation>Seçildiğinde, VirtualBox ağdan Misafir Eklentilerini indirme ya da güncellemeleri denetleme gibi görevler için doğrudan İnternet bağlantısı kullanacak.</translation>
     </message>
     <message>
         <source>&Direct Connection to the Internet</source>
@@ -4345,22 +4345,22 @@
     </message>
     <message>
         <source>When chosen, VirtualBox will use the proxy settings supplied for tasks like downloading Guest Additions from the network or checking for updates.</source>
-        <translation>Seçildiğinde, VirtualBox ağdan Misafir Eklentilerini indirme ya da güncellemeleri kontrol etme gibi görevler için sağlanan proksi ayarlarını kullanacak.</translation>
+        <translation>Seçildiğinde, VirtualBox ağdan Misafir Eklentilerini indirme ya da güncellemeleri denetleme gibi görevler için sağlanan vekil ayarlarını kullanacak.</translation>
     </message>
     <message>
         <source>&Manual Proxy Configuration</source>
-        <translation>&Elle Proksi Yapılandırması</translation>
+        <translation>&Elle Vekil Yapılandırması</translation>
     </message>
 </context>
 <context>
     <name>UIGlobalSettingsUpdate</name>
     <message>
         <source>When checked, the application will periodically connect to the VirtualBox website and check whether a new VirtualBox version is available.</source>
-        <translation>İşaretlendiğinde, uygulama VirtualBox web sitesine düzenli aralıklarla bağlanacak ve yeni bir VirtualBox sürümünün mevcut olup olmadıını kontrol edecektir.</translation>
+        <translation>İşaretlendiğinde, uygulama VirtualBox web sitesine düzenli aralıklarla bağlanacak ve yeni bir VirtualBox sürümünün mevcut olup olmadığını denetleyecektir.</translation>
     </message>
     <message>
         <source>&Check for Updates</source>
-        <translation>Güncellemeleri &kontrol et</translation>
+        <translation>Güncellemeleri &denetle</translation>
     </message>
     <message>
         <source>&Once per:</source>
@@ -4368,19 +4368,19 @@
     </message>
     <message>
         <source>Specifies how often the new version check should be performed. Note that if you want to completely disable this check, just clear the above check box.</source>
-        <translation type="obsolete">Yeni sürüm kontrolünün ne sıklıkla yapılacağını belirler. Eğer bu kontrolü tamamen etkisizleştirmek istiyorsanız, sadece yukarıdaki işaretleme kutusunun işaretini kaldırmayı unutmayın.</translation>
+        <translation type="obsolete">Yeni sürüm kontrolünün ne sıklıkla yapılacağını belirler. Eğer bu kontrolü tamamen etkisizleştirmek istiyorsanız, yalnızca yukarıdaki işaretleme kutusunun işaretini kaldırmayı unutmayın.</translation>
     </message>
     <message>
         <source>Next Check:</source>
-        <translation>Sonraki Kontrol:</translation>
+        <translation>Sonraki Denetleme:</translation>
     </message>
     <message>
         <source>Check for:</source>
-        <translation>Kontrol edilen:</translation>
+        <translation>Denetlenen:</translation>
     </message>
     <message>
         <source><p>Choose this if you only wish to be notified about stable updates to VirtualBox.</p></source>
-        <translation><p>Eğer sadece VirtualBox'ın sağlam güncellemeleri hakkında bilgilendirilmek istiyorsanız bunu seçin.</p></translation>
+        <translation><p>Eğer yalnızca VirtualBox'ın sağlam güncellemeleri hakkında bilgilendirilmek istiyorsanız bunu seçin.</p></translation>
     </message>
     <message>
         <source>&Stable Release Versions</source>
@@ -4404,7 +4404,7 @@
     </message>
     <message>
         <source>Selects how often the new version check should be performed. Note that if you want to completely disable this check, just clear the above check box.</source>
-        <translation>Yeni sürüm kontrolünün ne sıklıkla yapılması gerektiğini seçer. Eğer bu kontrolü tamamen etkisizleştirmek istiyorsanız, sadece yukarıdaki işaretleme kutusunun işaretini kaldırmayı unutmayın.</translation>
+        <translation>Yeni sürüm denetiminin ne sıklıkla yapılması gerektiğini seçer. Eğer bu denetimi tamamen etkisizleştirmek istiyorsanız, yalnızca yukarıdaki işaretleme kutusunun işaretini kaldırmayı unutmayın.</translation>
     </message>
 </context>
 <context>
@@ -4992,7 +4992,7 @@
     <message>
         <source>Host-only adapter, '%1'</source>
         <comment>details report (network)</comment>
-        <translation>Sadece-anamakine bağdaştırıcısı, '%1'</translation>
+        <translation>Yalnızca-anamakine bağdaştırıcısı, '%1'</translation>
     </message>
     <message>
         <source>Generic, '%1'</source>
@@ -5521,7 +5521,7 @@
     </message>
     <message>
         <source>you have 2D Video Acceleration enabled. As 2D Video Acceleration is supported for Windows guests only, this feature will be disabled.</source>
-        <translation type="obsolete">2B Görüntü Hızlandırmayı etkinleştirdiniz. 2B Görüntü Hızlandırma ancak sadece Windows misafirleri için desteklenir, bu özellik etkisizleştirilecektir.</translation>
+        <translation type="obsolete">2B Görüntü Hızlandırmayı etkinleştirdiniz. 2B Görüntü Hızlandırma ancak yalnızca Windows misafirleri için desteklenir, bu özellik etkisizleştirilecektir.</translation>
     </message>
     <message>
         <source>you enabled 3D acceleration. However, 3D acceleration is not working on the current host setup so you will not be able to start the VM.</source>
@@ -5605,7 +5605,7 @@
     </message>
     <message>
         <source>The virtual machine is set up to use Video Stream Acceleration. As this feature only works with Windows guest systems it will be disabled.</source>
-        <translation>Sanal makine, Görüntü Akışı Hızlandırmasını kullanması için ayarlanır. Bu özellik sadece Windows misafir sistemleri ile çalışır iken etkisizleştirilecektir.</translation>
+        <translation>Sanal makine, Görüntü Akışı Hızlandırmasını kullanması için ayarlanır. Bu özellik yalnızca Windows misafir sistemleri ile çalışır iken etkisizleştirilecektir.</translation>
     </message>
     <message>
         <source>The VRDE server port value is not currently specified.</source>
@@ -5696,7 +5696,7 @@
     </message>
     <message>
         <source>Controls the guest screen scale factor.</source>
-        <translation>Misafir ekranı ölçek etkenini kontrol eder.</translation>
+        <translation>Misafir ekranı ölçek etkenini denetler.</translation>
     </message>
     <message>
         <source>100%</source>
@@ -5975,7 +5975,7 @@
     </message>
     <message>
         <source>you have selected a 64-bit guest OS type for this VM. As such guests require hardware virtualization (VT-x/AMD-V), this feature will be enabled automatically.</source>
-        <translation type="obsolete">bu VM için 64-bit misafir İS türü seçtiniz. Bu gibi misafirler donanım sanallaştırma (VT-x/AMD-V) gerektirir, bu özellik otomatik olarak etkinleştirilecektir.</translation>
+        <translation type="obsolete">bu VM için 64-bit misafir İS türü seçtiniz. Bu gibi misafirler donanım sanallaştırma (VT-x/AMD-V) gerektirir, bu özellik kendiliğinden etkinleştirilecektir.</translation>
     </message>
     <message>
         <source>D&rag'n'Drop:</source>
@@ -5991,7 +5991,7 @@
     </message>
     <message>
         <source>The virtual machine operating system hint is set to a 64-bit type. 64-bit guest systems require hardware virtualization, so this will be enabled automatically if you confirm the changes.</source>
-        <translation>Sanal makine işletim sistemi ipucu 64-bit türüne ayarlı. 64-bit misafir sistemleri donanım sanallaştırması gerektirir, bu yüzden eğer değişiklikleri onaylarsanız, bu otomatik olarak etkinleştirilecektir.</translation>
+        <translation>Sanal makine işletim sistemi ipucu 64-bit türüne ayarlı. 64-bit misafir sistemleri donanım sanallaştırması gerektirir, bu yüzden eğer değişiklikleri onaylarsanız, bu kendiliğinden etkinleştirilecektir.</translation>
     </message>
     <message>
         <source>Enc&ryption</source>
@@ -6256,7 +6256,7 @@
     </message>
     <message>
         <source>no host-only network adapter is selected</source>
-        <translation type="obsolete">seçilen sadece-anamakine ağ bağdaştırıcısı yok</translation>
+        <translation type="obsolete">seçilen yalnızca-anamakine ağ bağdaştırıcısı yok</translation>
     </message>
     <message>
         <source>Not selected</source>
@@ -6293,7 +6293,7 @@
     </message>
     <message>
         <source>Selects the promiscuous mode policy of the network adapter when attached to an internal network, host only network or a bridge.</source>
-        <translation>Dahili bir ağa, sadece-anamakine ağına ya da bir köprüye takıldığında ağ bağdaştırıcısının karma kipi politikasını seçer.</translation>
+        <translation>Dahili bir ağa, yalnızca-anamakine ağına ya da bir köprüye takıldığında ağ bağdaştırıcısının karma kipi politikasını seçer.</translation>
     </message>
     <message>
         <source>Generic Properties:</source>
@@ -6329,7 +6329,7 @@
     </message>
     <message>
         <source>the second digit in the MAC address may not be odd as only unicast addresses are allowed.</source>
-        <translation type="obsolete">MAC adresindeki ikinci rakam tek olamaz iken sadece tek yöne yayınlama adreslerine izin verilir.</translation>
+        <translation type="obsolete">MAC adresindeki ikinci rakam tek olamaz iken yalnızca tek yöne yayınlama adreslerine izin verilir.</translation>
     </message>
     <message>
         <source>No bridged network adapter is currently selected.</source>
@@ -6341,7 +6341,7 @@
     </message>
     <message>
         <source>No host-only network adapter is currently selected.</source>
-        <translation>Şu anda belirtilmiş hiç sadece-anamakine ağ bağdaştırıcısı yok.</translation>
+        <translation>Şu anda belirtilmiş hiç yalnızca-anamakine ağ bağdaştırıcısı yok.</translation>
     </message>
     <message>
         <source>No generic driver is currently selected.</source>
@@ -6353,7 +6353,7 @@
     </message>
     <message>
         <source>The second digit in the MAC address may not be odd as only unicast addresses are allowed.</source>
-        <translation>MAC adresindeki ikinci rakam sadece tek yön yayın adreslerine izin verildiği gibi tek olamaz.</translation>
+        <translation>MAC adresindeki ikinci rakam yalnızca tek yön yayın adreslerine izin verildiği gibi tek olamaz.</translation>
     </message>
     <message>
         <source>No NAT network name is currently specified.</source>
@@ -6455,7 +6455,7 @@
     </message>
     <message>
         <source>Holds the IRQ number of this parallel port. This should be a whole number between <tt>0</tt> and <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> setting is enabled for this virtual machine.</source>
-        <translation>Bu paralel bağlantı noktasının IRQ numarasını tutar. Bu <tt>0</tt> ve <tt>255</tt> arasında bütün bir numara olmalıdır. Eğer bu sanal makine için <b>I/O APIC</b> ayarı etkinleştirilmişse sadece <tt>15</tt>'ten büyük değerler kullanılabilir.</translation>
+        <translation>Bu paralel bağlantı noktasının IRQ numarasını tutar. Bu <tt>0</tt> ve <tt>255</tt> arasında bütün bir numara olmalıdır. Eğer bu sanal makine için <b>I/O APIC</b> ayarı etkinleştirilmişse yalnızca <tt>15</tt>'ten büyük değerler kullanılabilir.</translation>
     </message>
     <message>
         <source>Holds the base I/O port address of this parallel port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
@@ -6624,7 +6624,7 @@
     </message>
     <message>
         <source>Auto-mount</source>
-        <translation>Otomatik-Bağla</translation>
+        <translation>Kendiliğinden-Bağla</translation>
     </message>
     <message>
         <source>Yes</source>
@@ -6695,11 +6695,11 @@
     </message>
     <message>
         <source>When checked, the guest OS will try to automatically mount the shared folder on startup.</source>
-        <translation>İşaretlendiğinde, misafir İS başlangıçta paylaşılan klasörü otomatik olarak bağlamayı deneyecektir.</translation>
+        <translation>İşaretlendiğinde, misafir İS başlangıçta paylaşılan klasörü kendiliğinden bağlamayı deneyecektir.</translation>
     </message>
     <message>
         <source>&Auto-mount</source>
-        <translation>&Otomatik-bağla</translation>
+        <translation>&Kendiliğinden-bağla</translation>
     </message>
     <message>
         <source>If checked, this shared folder will be permanent.</source>
@@ -6739,7 +6739,7 @@
     </message>
     <message>
         <source>Holds the IRQ number of this serial port. Valid values are integer numbers in range from <tt>0</tt> to <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> is enabled for this virtual machine.</source>
-        <translation type="obsolete">Seri portun IRQ numaralarını gösterir.  Geçerli değerler <tt>0</tt> ile <tt>255</tt> arasındaki tüm sayılardır. <tt>15</tt>'ten daha büyük sayılar sadece sanal makine için <b>I/O APIC</b> etkinleştirildiyse kullanılabilir.</translation>
+        <translation type="obsolete">Seri portun IRQ numaralarını gösterir.  Geçerli değerler <tt>0</tt> ile <tt>255</tt> arasındaki tüm sayılardır. <tt>15</tt>'ten daha büyük sayılar yalnızca sanal makine için <b>I/O APIC</b> etkinleştirildiyse kullanılabilir.</translation>
     </message>
     <message>
         <source>I/O Po&rt:</source>
@@ -6779,7 +6779,7 @@
     </message>
     <message>
         <source>Holds the IRQ number of this serial port. This should be a whole number between <tt>0</tt> and <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> setting is enabled for this virtual machine.</source>
-        <translation>Bu seri bağlantı noktasının IRQ numarasını tutar. Bu <tt>0</tt> ve <tt>255</tt> arasında bütün bir numara olmalıdır. Eğer bu sanal makine için <b>I/O APIC</b> ayarı etkinleştirilmişse sadece <tt>15</tt>'ten büyük değerler kullanılabilir.</translation>
+        <translation>Bu seri bağlantı noktasının IRQ numarasını tutar. Bu <tt>0</tt> ve <tt>255</tt> arasında bütün bir numara olmalıdır. Eğer bu sanal makine için <b>I/O APIC</b> ayarı etkinleştirilmişse yalnızca <tt>15</tt>'ten büyük değerler kullanılabilir.</translation>
     </message>
     <message>
         <source>Holds the base I/O port address of this serial port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
@@ -6901,7 +6901,7 @@
     </message>
     <message>
         <source><nobr>Expand/Collapse&nbsp;Item</nobr></source>
-        <translation type="obsolete"><nobr>Öğeyi&nbsp;Genişlet/Daralt</nobr></translation>
+        <translation type="obsolete"><nobr>Ögeyi&nbsp;Genişlet/Daralt</nobr></translation>
     </message>
     <message>
         <source><nobr>Add&nbsp;Hard&nbsp;Disk</nobr></source>
@@ -6917,7 +6917,7 @@
     </message>
     <message>
         <source><i>%1</i> uses a medium that is already attached to <i>%2</i>.</source>
-        <translation type="obsolete"><i>%1</i>, zaten <i>%2</i> cihazına takılı bir ortam kullanıyor.</translation>
+        <translation type="obsolete"><i>%1</i>, zaten <i>%2</i> aygıtına takılı bir ortam kullanıyor.</translation>
     </message>
     <message>
         <source>Add Controller</source>
@@ -7312,7 +7312,7 @@
     </message>
     <message>
         <source><nobr>Expands/Collapses&nbsp;item.</nobr></source>
-        <translation><nobr>Öğeyi&nbsp;Genişletir/Daraltır.</nobr></translation>
+        <translation><nobr>Ögeyi&nbsp;Genişletir/Daraltır.</nobr></translation>
     </message>
     <message>
         <source><nobr>Adds&nbsp;hard&nbsp;disk.</nobr></source>
@@ -7392,11 +7392,11 @@
     </message>
     <message>
         <source>you have assigned more than one virtual CPU to this VM. This will not work unless the IO-APIC feature is also enabled. This will be done automatically when you accept the VM Settings by pressing the OK button.</source>
-        <translation type="obsolete">bu VM'e birden fazla sanal işlemci atadınız. Bu, ayrıca IO-APIC özelliği etkinleştirilmedikçe çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">bu VM'e birden fazla sanal işlemci atadınız. Bu, ayrıca IO-APIC özelliği etkinleştirilmedikçe çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>you have assigned more than one virtual CPU to this VM. This will not work unless hardware virtualization (VT-x/AMD-V) is also enabled. This will be done automatically when you accept the VM Settings by pressing the OK button.</source>
-        <translation type="obsolete">bu VM'e birden fazla sanal işlemci atadınız. Bu, ayrıca donanım sanallaştırma (VT-x/AMD-V) etkinleştirilmedikçe çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">bu VM'e birden fazla sanal işlemci atadınız. Bu, ayrıca donanım sanallaştırma (VT-x/AMD-V) etkinleştirilmedikçe çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source><qt>%1&nbsp;MB</qt></source>
@@ -7429,7 +7429,7 @@
     </message>
     <message>
         <source>Defines the boot device order. Use the checkboxes on the left to enable or disable individual boot devices. Move items up and down to change the device order.</source>
-        <translation>Önyükleme aygıtının sırasını tanımlar. Kişisel önyükleme aygıtlarını etkinleştirmek ya da etkisizleştirmek için soldaki işaretleme kutularını kullanın. Aygıt sırasını değiştirmek için öğeleri yukarı ve aşağı taşıyın.</translation>
+        <translation>Önyükleme aygıtının sırasını tanımlar. Kişisel önyükleme aygıtlarını etkinleştirmek ya da etkisizleştirmek için soldaki işaretleme kutularını kullanın. Aygıt sırasını değiştirmek için ögeleri yukarı ve aşağı taşıyın.</translation>
     </message>
     <message>
         <source>Move Down (Ctrl-Down)</source>
@@ -7510,7 +7510,7 @@
     </message>
     <message>
         <source>Enable &EFI (special OSes only)</source>
-        <translation>&EFI etkinleştir (sadece özel İS'leri)</translation>
+        <translation>&EFI etkinleştir (yalnızca özel İS'leri)</translation>
     </message>
     <message>
         <source>If checked, the RTC device will report the time in UTC, otherwise in local (host) time. Unix usually expects the hardware clock to be set to UTC.</source>
@@ -7526,7 +7526,7 @@
     </message>
     <message>
         <source>If checked, an absolute pointing device (a USB tablet) will be supported. Otherwise, only a standard PS/2 mouse will be emulated.</source>
-        <translation type="obsolete">Eğer işaretlenmişse, mutlak işaretleme aygıtı (bir USB tablet) desteklenecektir. Aksi takdirde, sadece standart PS/2 fare uyarlanacaktır.</translation>
+        <translation type="obsolete">Eğer işaretlenmişse, mutlak işaretleme aygıtı (bir USB tablet) desteklenecektir. Aksi takdirde, yalnızca standart PS/2 fare uyarlanacaktır.</translation>
     </message>
     <message>
         <source>Enable &absolute pointing device</source>
@@ -7554,7 +7554,7 @@
     </message>
     <message>
         <source>you have enabled a USB HID (Human Interface Device). This will not work unless USB emulation is also enabled. This will be done automatically when you accept the VM Settings by pressing the OK button.</source>
-        <translation type="obsolete">USB HID'i (İnsan Arabirim Aygıtı) etkinleştirdiniz. USB uyarlaması ayrıca etkinleştirilmedikçe bu çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">USB HID'i (İnsan Arabirim Aygıtı) etkinleştirdiniz. USB uyarlaması ayrıca etkinleştirilmedikçe bu çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source><qt>%1%</qt></source>
@@ -7568,7 +7568,7 @@
     </message>
     <message>
         <source>you have assigned ICH9 chipset type to this VM. It will not work properly unless the IO-APIC feature is also enabled. This will be done automatically when you accept the VM Settings by pressing the OK button.</source>
-        <translation type="obsolete">bu VM'e ICH9 yonga seti atadınız. IO-APIC özelliği ayrıca etkinleştirilmedikçe düzgün bir şekilde çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">bu VM'e ICH9 yonga seti atadınız. IO-APIC özelliği ayrıca etkinleştirilmedikçe düzgün bir şekilde çalışmayacak. Bu, VM Ayarlarında TAMAM düğmesine basarak kabul ettiğinizde kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>&Pointing Device:</source>
@@ -7588,11 +7588,11 @@
     </message>
     <message>
         <source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support a chip set of type ICH9. It will be done automatically if you confirm your changes.</source>
-        <translation type="obsolete">G/Ç APIC özelliği şu anda Sistem sayfasının Anakart bölümünde etkin değil. Bu, ICH9 türü bir yonga setini desteklemek için gereklidir. Eğer değişiklikleri onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">G/Ç APIC özelliği şu anda Sistem sayfasının Anakart bölümünde etkin değil. Bu, ICH9 türü bir yonga setini desteklemek için gereklidir. Eğer değişiklikleri onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>USB controller emulation is not currently enabled on the USB page. This is needed to support an emulated USB input device. It will be done automatically if you confirm your changes.</source>
-        <translation type="obsolete">USB denetleyicisi uyarlama şu anda USB sayfasında etkin değil. Bu, bir uyarlanmış USB girdi aygıtı desteklemek için gereklidir. Eğer değişiklikleri onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">USB denetleyicisi uyarlama şu anda USB sayfasında etkin değil. Bu, bir uyarlanmış USB girdi aygıtı desteklemek için gereklidir. Eğer değişiklikleri onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>For performance reasons, the number of virtual CPUs attached to the virtual machine may not be more than twice the number of physical CPUs on the host (<b>%1</b>). Please reduce the number of virtual CPUs.</source>
@@ -7604,11 +7604,11 @@
     </message>
     <message>
         <source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support more than one virtual processor. It will be done automatically if you confirm your changes.</source>
-        <translation type="obsolete">G/Ç APIC özelliği şu anda Sistem sayfasının Anakart bölümünde etkin değil. Bu, birden fazla sanal işlemciyi desteklemek için gerelidir. Eğer değişiklikleri onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">G/Ç APIC özelliği şu anda Sistem sayfasının Anakart bölümünde etkin değil. Bu, birden fazla sanal işlemciyi desteklemek için gerelidir. Eğer değişiklikleri onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>Hardware virtualization is not currently enabled in the Acceleration section of the System page. This is needed in order to support more than one virtual processor. It will be done automatically if you confirm your changes.</source>
-        <translation type="obsolete">Donanım hızlandırma şu anda Sistem sayfasının Hızlandırma bölümünde etkin değil. Bu, birden fazla sanal işlemciyi desteklemek için gerelidir. Eğer değişiklikleri onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation type="obsolete">Donanım hızlandırma şu anda Sistem sayfasının Hızlandırma bölümünde etkin değil. Bu, birden fazla sanal işlemciyi desteklemek için gerelidir. Eğer değişiklikleri onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>The processor execution cap is set to a low value. This may make the machine feel slow to respond.</source>
@@ -7624,19 +7624,19 @@
     </message>
     <message>
         <source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support a chip set of type ICH9 you have enabled for this VM. It will be done automatically if you confirm your changes.</source>
-        <translation>G/Ç APIC özelliği şu an Sistem sayfasının Anakart bölümünde etkinleştirilmedi. Bu, sizin bu VM için etkinleştirdiğiniz ICH9 türü bir yonga setini desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation>G/Ç APIC özelliği şu an Sistem sayfasının Anakart bölümünde etkinleştirilmedi. Bu, sizin bu VM için etkinleştirdiğiniz ICH9 türü bir yonga setini desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>USB controller emulation is not currently enabled on the USB page. This is needed to support an emulated USB input device you have enabled for this VM. It will be done automatically if you confirm your changes.</source>
-        <translation>USB denetleyicisi benzetimi şu an USB sayfasında etkinleştirilmedi. Bu, sizin bu VM için etkinleştirdiğiniz bir benzetilen USB girdi aygıtı desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation>USB denetleyicisi benzetimi şu an USB sayfasında etkinleştirilmedi. Bu, sizin bu VM için etkinleştirdiğiniz bir benzetilen USB girdi aygıtı desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support more than one virtual processor you have chosen for this VM. It will be done automatically if you confirm your changes.</source>
-        <translation>G/Ç APIC özelliği şu an Sistem sayfasının Anakart bölümünde etkinleştirilmedi. Bu, sizin bu VM için seçtiğiniz birden fazla sanal işlemciyi desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation>G/Ç APIC özelliği şu an Sistem sayfasının Anakart bölümünde etkinleştirilmedi. Bu, sizin bu VM için seçtiğiniz birden fazla sanal işlemciyi desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>Hardware virtualization is not currently enabled in the Acceleration section of the System page. This is needed in order to support more than one virtual processor you have chosen for this VM. It will be done automatically if you confirm your changes.</source>
-        <translation>Donanım sanallaştırma şu an Sistem sayfasının Hızlandırma bölümünde etkinleştirilmedi. Bu, sizin bu VM için seçtiğiniz birden fazla sanal işlemciyi desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu otomatik olarak yapılacaktır.</translation>
+        <translation>Donanım sanallaştırma şu an Sistem sayfasının Hızlandırma bölümünde etkinleştirilmedi. Bu, sizin bu VM için seçtiğiniz birden fazla sanal işlemciyi desteklemek için gereklidir. Eğer değişikliklerinizi onaylarsanız, bu kendiliğinden yapılacaktır.</translation>
     </message>
     <message>
         <source>When checked, the RTC device will report the time in UTC, otherwise in local (host) time. Unix usually expects the hardware clock to be set to UTC.</source>
@@ -8152,7 +8152,7 @@
     <message>
         <source>Do not show this message again</source>
         <comment>msg box flag</comment>
-        <translation>Bu iletiyi tekrar gösterme</translation>
+        <translation>Bu iletiyi yeniden gösterme</translation>
     </message>
     <message>
         <source>Failed to open <tt>%1</tt>. Make sure your desktop environment can properly handle URLs of this type.</source>
@@ -8455,7 +8455,7 @@
     </message>
     <message>
         <source><p>Failed to remove the shared folder <b>%1</b> (pointing to <nobr><b>%2</b></nobr>) from the virtual machine <b>%3</b>.</p><p>Please close all programs in the guest OS that may be using this shared folder and try again.</p></source>
-        <translation><p><b>%3</b>sanal makinesinden <b>%1</b> paylaşılan klasörünü (<nobr><b>%2</b></nobr> klasörünü işaret eden) kaldırma başarısız.</p><p>Lütfen misafir İS içerisinde bu paylaşılan klasörü kullanabilen tüm programları kapatın ve tekrar deneyin.</p></translation>
+        <translation><p><b>%3</b>sanal makinesinden <b>%1</b> paylaşılan klasörünü (<nobr><b>%2</b></nobr> klasörünü işaret eden) kaldırma başarısız.</p><p>Lütfen misafir İS içerisinde bu paylaşılan klasörü kullanabilen tüm programları kapatın ve yeniden deneyin.</p></translation>
     </message>
     <message>
         <source><p>Could not find the VirtualBox Guest Additions disk image file file <nobr><b>%1</b></nobr> or <nobr><b>%2</b>.</nobr></p><p>Do you wish to download this disk image file from the Internet?</p></source>
@@ -8483,7 +8483,7 @@
     </message>
     <message>
         <source>Failed to open the license file <nobr><b>%1</b></nobr>. Check file permissions.</source>
-        <translation><nobr><b>%1</b></nobr> lisans dosyasını açma başarısız. Dosya izinlerini kontrol edin.</translation>
+        <translation><nobr><b>%1</b></nobr> lisans dosyasını açma başarısız. Dosya izinlerini denetleyin.</translation>
     </message>
     <message>
         <source>Failed to send the ACPI Power Button press event to the virtual machine <b>%1</b>.</source>
@@ -8579,7 +8579,7 @@
     <message>
         <source>Check</source>
         <comment>inaccessible media message box</comment>
-        <translation>Kontrol et</translation>
+        <translation>Denetle</translation>
     </message>
     <message>
         <source>&Save</source>
@@ -8653,15 +8653,15 @@
     </message>
     <message>
         <source><p>You have <b>clicked the mouse</b> inside the Virtual Machine display or pressed the <b>host key</b>. This will cause the Virtual Machine to <b>capture</b> the host mouse pointer (only if the mouse pointer integration is not currently supported by the guest OS) and the keyboard, which will make them unavailable to other applications running on your host machine.</p><p>You can press the <b>host key</b> at  [...]
-        <translation><p>Sanal Makine ekranında <b>fareye tıkladınız</b> ya da <b>anamakine tuşuna</b> bastınız. Bu, Sanal Makinenin anamakinenizde çalışan diğer uygulamalar için kullanılamaz yapacak olan anamakine fare işaretçisini (eğer sadece fare işaretçisi bütünleştirme misafir İS tarafından şu anda desteklenmiyorsa) ve klavyesini <b>yakalamasına</b> neden olacak.</p><p>İstediğiniz zaman klavyeyi ve fareyi (eğer yakalandıysa) < [...]
+        <translation><p>Sanal Makine ekranında <b>fareye tıkladınız</b> ya da <b>anamakine tuşuna</b> bastınız. Bu, Sanal Makinenin anamakinenizde çalışan diğer uygulamalar için kullanılamaz yapacak olan anamakine fare işaretçisini (eğer yalnızca fare işaretçisi bütünleştirme misafir İS tarafından şu anda desteklenmiyorsa) ve klavyesini <b>yakalamasına</b> neden olacak.</p><p>İstediğiniz zaman klavyeyi ve fareyi (eğer yakalandıysa) &l [...]
     </message>
     <message>
         <source><p>You have the <b>Auto capture keyboard</b> option turned on. This will cause the Virtual Machine to automatically <b>capture</b> the keyboard every time the VM window is activated and make it unavailable to other applications running on your host machine: when the keyboard is captured, all keystrokes (including system ones like Alt-Tab) will be directed to the VM.</p><p>You can press the <b>host key</b> at any time t [...]
-        <translation><p><b>Klavyeyi otomatik yakala</b> seçeneğiniz açılmış. Bu, VM penceresinin etkinleştirildiği her seferde Sanal Makinenin klavyenizi otomatik olarak <b>yakalamasına</b> neden olacak ve anamakinenizde çalışan diğer uygulamar için kullanılamaz yapacak: klavye yakalandığında tüm tuşa basmalar (Alt-Tab gibi sistem için olanlar da dahil) VM'eyönlendirilecektir.</p><p>İstediğiniz zaman klavyeyi ve fareyi (eğer yakalandıysa) &l [...]
+        <translation><p><b>Klavyeyi kendiliğinden yakala</b> seçeneğiniz açılmış. Bu, VM penceresinin etkinleştirildiği her seferde Sanal Makinenin klavyenizi kendiliğinden <b>yakalamasına</b> neden olacak ve anamakinenizde çalışan diğer uygulamar için kullanılamaz yapacak: klavye yakalandığında tüm tuşa basmalar (Alt-Tab gibi sistem için olanlar da dahil) VM'eyönlendirilecektir.</p><p>İstediğiniz zaman klavyeyi ve fareyi (eğer yakalandıysa) [...]
     </message>
     <message>
         <source><p>The Virtual Machine reports that the guest OS supports <b>mouse pointer integration</b>. This means that you do not need to <i>capture</i> the mouse pointer to be able to use it in your guest OS -- all mouse actions you perform when the mouse pointer is over the Virtual Machine's display are directly sent to the guest OS. If the mouse is currently captured, it will be automatically uncaptured.</p><p>The mouse icon on the s [...]
-        <translation><p>Sanal Makine misafir İS'nin <b>fare işaretçisi bütünleştirmeyi</b> desteklediğini bildiriyor. Bu, fare işaretçisinin misafir İS'niz içinde kullanılabilmesi için <i>yakalamanıza</i> gerek olmadığı anlamına geliyor -- Sanal Makine ekranının üzerine fare işaretçisi geldiğinde gerçekleştirdiğiniz tüm fare eylemleri doğrudan misafir İS'ne gönderilir. Eğer fare şu anda yakalanırsa, otomatik olarak serbest bırakılacaktır.</ [...]
+        <translation><p>Sanal Makine misafir İS'nin <b>fare işaretçisi bütünleştirmeyi</b> desteklediğini bildiriyor. Bu, fare işaretçisinin misafir İS'niz içinde kullanılabilmesi için <i>yakalamanıza</i> gerek olmadığı anlamına geliyor -- Sanal Makine ekranının üzerine fare işaretçisi geldiğinde gerçekleştirdiğiniz tüm fare eylemleri doğrudan misafir İS'ne gönderilir. Eğer fare şu anda yakalanırsa, kendiliğinden serbest bırakılacaktır.</p& [...]
     </message>
     <message>
         <source>&Contents...</source>
@@ -8717,7 +8717,7 @@
     </message>
     <message>
         <source><p>Are you sure you want to release the %1 <nobr><b>%2</b></nobr>?</p><p>This will detach it from the following virtual machine(s): <b>%3</b>.</p></source>
-        <translation type="obsolete"><p><nobr><b>%2</b></nobr> %1 öğesini serbest bırakmak istediğinize emin misiniz?</p><p>Bu, kalıbı şurada belirtilen sanal makine(ler)den çıkartacak: <b>%3</b>.</p></translation>
+        <translation type="obsolete"><p><nobr><b>%2</b></nobr> %1 ögesini serbest bırakmak istediğinize emin misiniz?</p><p>Bu, kalıbı şurada belirtilen sanal makine(ler)den çıkartacak: <b>%3</b>.</p></translation>
     </message>
     <message>
         <source>Release</source>
@@ -8726,7 +8726,7 @@
     </message>
     <message>
         <source><p>Are you sure you want to remove the %1 <nobr><b>%2</b></nobr> from the list of known disk image files?</p></source>
-        <translation type="obsolete"><p><nobr><b>%2</b></nobr> %1 öğesini bilinen ortam listesinden kaldırmak istediğinize emin misiniz?</p></translation>
+        <translation type="obsolete"><p><nobr><b>%2</b></nobr> %1 ögesini bilinen ortam listesinden kaldırmak istediğinize emin misiniz?</p></translation>
     </message>
     <message>
         <source>As this hard disk is inaccessible its image file can not be deleted.</source>
@@ -8747,7 +8747,7 @@
     </message>
     <message>
         <source><p>Do you want to delete the storage unit of the hard disk <nobr><b>%1</b></nobr>?</p><p>If you select <b>Delete</b> then the specified storage unit will be permanently deleted. This operation <b>cannot be undone</b>.</p><p>If you select <b>Keep</b> then the hard disk will be only removed from the list of known hard disks, but the storage unit will be left untouched which makes it po [...]
-        <translation type="obsolete"><p><nobr><b>%1</b></nobr> sabit diskinin depolama birimini silmek istediğinize emin misiniz?</p><p>Eğer <b>Sil</b>'i seçerseniz sonrasında belirtilmiş depolama birimi kalıcı olarak silinecektir. Bu işlem <b>geri alınamaz</b>.</p><p>Eğer <b>Keep</b>'u seçerseniz sonrasında sabit disk sadece bilinen sabit diskler listesinden kaldırılacaktır ama daha sonra [...]
+        <translation type="obsolete"><p><nobr><b>%1</b></nobr> sabit diskinin depolama birimini silmek istediğinize emin misiniz?</p><p>Eğer <b>Sil</b>'i seçerseniz sonrasında belirtilmiş depolama birimi kalıcı olarak silinecektir. Bu işlem <b>geri alınamaz</b>.</p><p>Eğer <b>Keep</b>'u seçerseniz sonrasında sabit disk yalnızca bilinen sabit diskler listesinden kaldırılacaktır ama daha son [...]
     </message>
     <message>
         <source>Delete</source>
@@ -8867,43 +8867,43 @@
     </message>
     <message>
         <source>Failed to create the host-only network interface.</source>
-        <translation type="obsolete">Sadece-anamakine ağ arayüzünü oluşturma başarısız.</translation>
+        <translation type="obsolete">Yalnızca-anamakine ağ arayüzünü oluşturma başarısız.</translation>
     </message>
     <message>
         <source><p>Your existing VirtualBox settings files will be automatically converted from the old format to a new format required by the new version of VirtualBox.</p><p>Press <b>OK</b> to start VirtualBox now or press <b>Exit</b> if you want to terminate the VirtualBox application without any further actions.</p></source>
-        <translation type="obsolete"><p>Mevcut VirtualBox ayar dosyalarınız otomatik olarak eski biçimden VirtualBox'ın yeni sürümünün gerektirdiği yeni bir biçime dönüştürülecek.</p><p>VirtualBox'ı hemen başlatmak için <b>TAMAM</b> düğmesine basın ya da herhangi bir başka eylemler olmadan VirtualBox uygulamasını sonlandırmak istiyorsanız, <b>Çıkış</b> düğmesine basın.</p></translation>
+        <translation type="obsolete"><p>Mevcut VirtualBox ayar dosyalarınız kendiliğinden eski biçimden VirtualBox'ın yeni sürümünün gerektirdiği yeni bir biçime dönüştürülecek.</p><p>VirtualBox'ı hemen başlatmak için <b>TAMAM</b> düğmesine basın ya da herhangi bir başka eylemler olmadan VirtualBox uygulamasını sonlandırmak istiyorsanız, <b>Çıkış</b> düğmesine basın.</p></translation>
     </message>
     <message>
         <source>Failed to open appliance.</source>
-        <translation type="obsolete">Cihazı açma başarısız.</translation>
+        <translation type="obsolete">Aygıtı açma başarısız.</translation>
     </message>
     <message>
         <source>Failed to open/interpret appliance <b>%1</b>.</source>
-        <translation><b>%1</b> cihazını açma/canlandırma başarısız.</translation>
+        <translation><b>%1</b> aygıtını açma/canlandırma başarısız.</translation>
     </message>
     <message>
         <source>Failed to import appliance <b>%1</b>.</source>
-        <translation><b>%1</b> cihazını içe aktarma başarısız.</translation>
+        <translation><b>%1</b> aygıtını içe aktarma başarısız.</translation>
     </message>
     <message>
         <source>Failed to create appliance.</source>
-        <translation type="obsolete">Cihaz oluşturma başarısız.</translation>
+        <translation type="obsolete">Aygıt oluşturma başarısız.</translation>
     </message>
     <message>
         <source>Failed to prepare the export of the appliance <b>%1</b>.</source>
-        <translation><b>%1</b> cihazını dışa aktarılmaya hazırlama başarısız.</translation>
+        <translation><b>%1</b> aygıtını dışa aktarılmaya hazırlama başarısız.</translation>
     </message>
     <message>
         <source>Failed to create an appliance.</source>
-        <translation type="obsolete">Bir cihaz oluşturma başarısız.</translation>
+        <translation type="obsolete">Bir aygıt oluşturma başarısız.</translation>
     </message>
     <message>
         <source>Failed to export appliance <b>%1</b>.</source>
-        <translation><b>%1</b> cihazını dışa aktarma başarısız.</translation>
+        <translation><b>%1</b> aygıtını dışa aktarma başarısız.</translation>
     </message>
     <message>
         <source><p>Deleting this host-only network will remove the host-only interface this network is based on. Do you want to remove the (host-only network) interface <nobr><b>%1</b>?</nobr></p><p><b>Note:</b> this interface may be in use by one or more virtual network adapters belonging to one of your VMs. After it is removed, these adapters will no longer be usable until you correct their settings by either choosing a different in [...]
-        <translation><p>Sadece-anamakine ağını silmek bu ağ tabanlı sadece-anamakine arayüzünü kaldıracak. <nobr><b>%1</b></nobr> (sadece-anamakine ağı) arayüzünü kaldırma istiyor musunuz?</p><p><b>Not:</b> bu arayüz VM'lerinizden birine ait olan bir ya da daha fazla sanal ağ bağdaştırıcıları tarafından kullanımda olabilir. Kaldırıldıktan sonra, bu bağdaştırıcılar ya farklı bir arayüz adı ya da farklı bir bağdaştırıcı eklenti tür [...]
+        <translation><p>Yalnızca-anamakine ağını silmek bu ağ tabanlı yalnızca-anamakine arayüzünü kaldıracak. <nobr><b>%1</b></nobr> (yalnızca-anamakine ağı) arayüzünü kaldırma istiyor musunuz?</p><p><b>Not:</b> bu arayüz VM'lerinizden birine ait olan bir ya da daha fazla sanal ağ bağdaştırıcıları tarafından kullanımda olabilir. Kaldırıldıktan sonra, bu bağdaştırıcılar ya farklı bir arayüz adı ya da farklı bir bağdaştırıcı eklen [...]
     </message>
     <message>
         <source>A file named <b>%1</b> already exists. Are you sure you want to replace it?<br /><br />Replacing it will overwrite its contents.</source>
@@ -8923,7 +8923,7 @@
     </message>
     <message>
         <source>Failed to check files.</source>
-        <translation>Dosyaları kontrol etme başarısız.</translation>
+        <translation>Dosyaları denetleme başarısız.</translation>
     </message>
     <message>
         <source>Failed to remove file.</source>
@@ -8998,7 +8998,7 @@
     </message>
     <message>
         <source><p>The following VirtualBox settings files will be automatically converted from the old format to a new format required by the new version of VirtualBox.</p><p>Press <b>OK</b> to start VirtualBox now or press <b>Exit</b> if you want to terminate the VirtualBox application without any further actions.</p></source>
-        <translation type="obsolete"><p>Aşağıdaki VirtualBox ayar dosyalarınız otomatik olarak eski biçimden VirtualBox'ın yeni sürümünün gerektirdiği yeni bir biçime dönüştürülecek.</p><p>VirtualBox'ı hemen başlatmak için <b>TAMAM</b> düğmesine basın ya da herhangi bir başka eylemler olmadan VirtualBox uygulamasını sonlandırmak istiyorsanız, <b>Çıkış</b> düğmesine basın.</p></translation>
+        <translation type="obsolete"><p>Aşağıdaki VirtualBox ayar dosyalarınız kendiliğinden eski biçimden VirtualBox'ın yeni sürümünün gerektirdiği yeni bir biçime dönüştürülecek.</p><p>VirtualBox'ı hemen başlatmak için <b>TAMAM</b> düğmesine basın ya da herhangi bir başka eylemler olmadan VirtualBox uygulamasını sonlandırmak istiyorsanız, <b>Çıkış</b> düğmesine basın.</p></translation>
     </message>
     <message>
         <source>hard disk</source>
@@ -9049,7 +9049,7 @@
     </message>
     <message>
         <source><p>Deleting the snapshot %1 will temporarily need more disk space. In the worst case the size of image %2 will grow by %3, however on this filesystem there is only %4 free.</p><p>Running out of disk space during the merge operation can result in corruption of the image and the VM configuration, i.e. loss of the VM and its data.</p><p>You may continue with deleting the snapshot at your own risk.</p></source>
-        <translation type="obsolete"><p>%1 anlık görüntüsünü silmek geçici olarak daha fazla disk alanı gerektirecek. En kötü halde %2 kalıbının boyutu %3 kadar büyüyecek ancak bu dosya sisteminde sadece %4 boşluk var.</p><p>Birleştirme işlemi sırasında yetersiz disk alanında çalışmak VM yapılandırmasının ve kalıbın bozulmasıyla sunuçlanabilir, yani VM'in ve verisinin kaybolması.</p><p>Riski size ait olan anlık görüntüyü silerek devam edebilirsiniz.< [...]
+        <translation type="obsolete"><p>%1 anlık görüntüsünü silmek geçici olarak daha fazla disk alanı gerektirecek. En kötü halde %2 kalıbının boyutu %3 kadar büyüyecek ancak bu dosya sisteminde yalnızca %4 boşluk var.</p><p>Birleştirme işlemi sırasında yetersiz disk alanında çalışmak VM yapılandırmasının ve kalıbın bozulmasıyla sunuçlanabilir, yani VM'in ve verisinin kaybolması.</p><p>Riski size ait olan anlık görüntüyü silerek devam edebilirsiniz.&l [...]
     </message>
     <message>
         <source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
@@ -9097,7 +9097,7 @@
     </message>
     <message>
         <source>Remove only</source>
-        <translation>Sadece kaldır</translation>
+        <translation>Yalnızca kaldır</translation>
     </message>
     <message>
         <source>Remove</source>
@@ -9185,7 +9185,7 @@
     </message>
     <message>
         <source><p>Note that the storage unit of this medium will not be deleted and that it will be possible to use it later again.</p></source>
-        <translation><p>Bu ortamın depolama biriminin silinmeyeceğini ve de daha sonra tekrar kullanmanın mümkün olacağını unutmayın.</p></translation>
+        <translation><p>Bu ortamın depolama biriminin silinmeyeceğini ve de daha sonra yeniden kullanmanın mümkün olacağını unutmayın.</p></translation>
     </message>
     <message>
         <source><p>The VirtualBox Guest Additions do not appear to be available on this virtual machine, and shared folders cannot be used without them. To use shared folders inside the virtual machine, please install the Guest Additions if they are not installed, or re-install them if they are not working correctly, by selecting <b>Install Guest Additions</b> from the <b>Devices</b> menu. If they are installed but the machine is not yet fully started then s [...]
@@ -9214,7 +9214,7 @@
     </message>
     <message>
         <source><p>You are about to install a VirtualBox extension pack. Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name:&nbsp;&nbsp;</b></td><td>%1< [...]
-        <translation><p>Bir VirtualBox genişletme paketini yüklemek üzeresiniz. Genişletme paketleri VirtualBox'ın işlevselliğini tamamlar ve sisteminize zarar verebilme ihtimali olabilen sistem seviyesinde yazılım içerebilir. Lütfen aşağıdan açıklamayı gözden geçirin ve sadece genişletme paketini güvenilir bir kaynaktan elde ettiyseniz ilerleyin.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Adı:&nbsp;&nbsp;</b></td&g [...]
+        <translation><p>Bir VirtualBox genişletme paketini yüklemek üzeresiniz. Genişletme paketleri VirtualBox'ın işlevselliğini tamamlar ve sisteminize zarar verebilme ihtimali olabilen sistem seviyesinde yazılım içerebilir. Lütfen aşağıdan açıklamayı gözden geçirin ve yalnızca genişletme paketini güvenilir bir kaynaktan elde ettiyseniz ilerleyin.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Adı:&nbsp;&nbsp;</b></td [...]
     </message>
     <message>
         <source>&Install</source>
@@ -9222,7 +9222,7 @@
     </message>
     <message>
         <source>Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</source>
-        <translation>Genişletme paketleri VirtualBox'ın işlevselliğini tamamlar ve sisteminize zarar verebilme ihtimali olabilen sistem seviyesinde yazılım içerebilir. Lütfen aşağıdan açıklamayı gözden geçirin ve sadece genişletme paketini güvenilir bir kaynaktan elde ettiyseniz ilerleyin.</translation>
+        <translation>Genişletme paketleri VirtualBox'ın işlevselliğini tamamlar ve sisteminize zarar verebilme ihtimali olabilen sistem seviyesinde yazılım içerebilir. Lütfen aşağıdan açıklamayı gözden geçirin ve yalnızca genişletme paketini güvenilir bir kaynaktan elde ettiyseniz ilerleyin.</translation>
     </message>
     <message>
         <source><p>An older version of the extension pack is already installed, would you like to upgrade? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name:&nbsp;&nbsp;</b></td><td>%2</td></tr><tr><td><b>New Version:&nbsp;&nbsp;</b></td><td>%3</td></tr><tr><td><b>Current Version:&nbsp;&nbsp;</b></td& [...]
@@ -9258,7 +9258,7 @@
     </message>
     <message>
         <source><p>Cannot create the machine folder <b>%1</b> in the parent folder <nobr><b>%2</b>.</nobr></p><p>Please check that the parent really exists and that you have permissions to create the machine folder.</p></source>
-        <translation><p><b>%1</b> makine klasörü <nobr><b>%2</b></nobr> ana klasöründe oluşturulamıyor.</p><p>Lütfen ana klasörün mevcut olduğunu ve makine klasörünü oluşturmak için izinlere sahip olduğunuzu kontrol edin.</p></translation>
+        <translation><p><b>%1</b> makine klasörü <nobr><b>%2</b></nobr> ana klasöründe oluşturulamıyor.</p><p>Lütfen ana klasörün mevcut olduğunu ve makine klasörünü oluşturmak için izinlere sahip olduğunuzu denetleyin.</p></translation>
     </message>
     <message>
         <source>Failed to register the virtual machine <b>%1</b>.</source>
@@ -9278,7 +9278,7 @@
     </message>
     <message>
         <source>The virtual machine that you are changing has been started. Only certain settings can be changed while a machine is running. All other changes will be lost if you close this window now.</source>
-        <translation>Değiştirmekte olduğunuz sanal makine başlatıdı. Makine çalışıyorken sadece belli ayarlar değiştirilebilir. Tüm diğer değişiklikler eğer bu pencereyi şimdi kapatırsanız kaybolacaktır.</translation>
+        <translation>Değiştirmekte olduğunuz sanal makine başlatıdı. Makine çalışıyorken yalnızca belli ayarlar değiştirilebilir. Tüm diğer değişiklikler eğer bu pencereyi şimdi kapatırsanız kaybolacaktır.</translation>
     </message>
     <message>
         <source>Failed to clone the virtual machine <b>%1</b>.</source>
@@ -9290,7 +9290,7 @@
     </message>
     <message>
         <source><p>Error changing disk image mode from <b>%1</b> to <b>%2</b>.</p></source>
-        <translation><p>Disk kalıbı kipini <b>%1</b> öğesinden <b>%2</b> öğesine değiştirilirken hata oldu.</p></translation>
+        <translation><p>Disk kalıbı kipini <b>%1</b> ögesinden <b>%2</b> ögesine değiştirilirken hata oldu.</p></translation>
     </message>
     <message>
         <source>Sorry, some generic error happens.</source>
@@ -9302,7 +9302,7 @@
     </message>
     <message>
         <source>Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer</source>
-        <translation>Anamakine USB Proksi Hizmeti (VERR_FILE_NOT_FOUND) yüklenemedi. Hizmet anamakine bilgisayarına yüklenememiştir</translation>
+        <translation>Anamakine USB Vekil Hizmeti (VERR_FILE_NOT_FOUND) yüklenemedi. Hizmet anamakine bilgisayarına yüklenememiştir</translation>
     </message>
     <message>
         <source>VirtualBox is not currently allowed to access USB devices.  You can change this by adding your user to the 'vboxusers' group.  Please see the user manual for a more detailed explanation</source>
@@ -9314,11 +9314,11 @@
     </message>
     <message>
         <source>The USB Proxy Service has not yet been ported to this host</source>
-        <translation>USB Proksi Hizmeti bu anamakineye henüz bağlantı noktası açmamış</translation>
+        <translation>USB Vekil Hizmeti bu anamakineye henüz bağlantı noktası açmamış</translation>
     </message>
     <message>
         <source>Could not load the Host USB Proxy service</source>
-        <translation>Anamakine USB Proksi hizmeti yüklenemedi</translation>
+        <translation>Anamakine USB Vekil hizmeti yüklenemedi</translation>
     </message>
     <message>
         <source>Can't find snapshot named <b>%1</b>.</source>
@@ -9330,7 +9330,7 @@
     </message>
     <message>
         <source><p>You have an old version (%1) of the <b><nobr>%2</nobr></b> installed.</p><p>Do you wish to download latest one from the Internet?</p></source>
-        <translation><p><b><nobr>%2</nobr></b> öğesinin yüklü eski bir sürümüne (%1) sahipsiniz.</p><p>En son olanı Internet'ten indirmek ister misiniz?</p></translation>
+        <translation><p><b><nobr>%2</nobr></b> ögesinin yüklü eski bir sürümüne (%1) sahipsiniz.</p><p>En son olanı Internet'ten indirmek ister misiniz?</p></translation>
     </message>
     <message>
         <source>Download</source>
@@ -9339,7 +9339,7 @@
     </message>
     <message>
         <source><p>Are you sure you want to download the <b><nobr>%1</nobr></b> from <nobr><a href="%2">%2</a></nobr> (size %3 bytes)?</p></source>
-        <translation><p><b><nobr>%1</nobr></b> öğesini <nobr><a href="%2">%2</a></nobr> (boyut %3 bayt) adresinden indirmek istediğinize emin misiniz?</p></translation>
+        <translation><p><b><nobr>%1</nobr></b> ögesini <nobr><a href="%2">%2</a></nobr> (boyut %3 bayt) adresinden indirmek istediğinize emin misiniz?</p></translation>
     </message>
     <message>
         <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>.</nobr></p><p>Do you wish to install this extension pack?</p></source>
@@ -9365,7 +9365,7 @@
     </message>
     <message>
         <source><p>Failed to initialize COM because the VirtualBox global configuration directory <b><nobr>%1</nobr></b> is not accessible. Please check the permissions of this directory and of its parent directory.</p><p>The application will now terminate.</p></source>
-        <translation>COM'u başlatma başarısız çünkü <b><nobr>%1</nobr></b> VirtualBox genel yapılandırma dizini erişilebilir değil. Lütfen bu dizinin ve ana dizininin izinlerini kontrol edin.</p><p>Uygulama şimdi sonlandırılacak.</p></translation>
+        <translation>COM'u başlatma başarısız çünkü <b><nobr>%1</nobr></b> VirtualBox genel yapılandırma dizini erişilebilir değil. Lütfen bu dizinin ve ana dizininin izinlerini denetleyin.</p><p>Uygulama şimdi sonlandırılacak.</p></translation>
     </message>
     <message numerus="yes">
         <source><p>The %n following virtual machine(s) are currently in a saved state: <b>%1</b></p><p>If you continue the runtime state of the exported machine(s) will be discarded. The other machine(s) will not be changed.</p></source>
@@ -9376,7 +9376,7 @@
     </message>
     <message>
         <source><p>You are about to remove following virtual machine items from the machine list:</p><p><b>%1</b></p><p>Do you wish to proceed?</p></source>
-        <translation><p>Aşağıdaki sanal makine öğelerini makine listesinden kaldırmak üzeresiniz:</p><p><b>%1</b></p><p>İlerlemek ister misiniz?</p></translation>
+        <translation><p>Aşağıdaki sanal makine ögelerini makine listesinden kaldırmak üzeresiniz:</p><p><b>%1</b></p><p>İlerlemek ister misiniz?</p></translation>
     </message>
     <message>
         <source><p>You are about to remove following inaccessible virtual machines from the machine list:</p><p>%1</p><p>Do you wish to proceed?</p></source>
@@ -9406,7 +9406,7 @@
     </message>
     <message>
         <source><p>Cannot remove the machine folder <nobr><b>%1</b>.</nobr></p><p>Please check that this folder really exists and that you have permissions to remove it.</p></source>
-        <translation><p><nobr><b>%1</b></nobr> makine klasörü kaldırılamıyor.</p><p>Lütfen bu klasörün gerçekten var olduğunu ve kaldırmak için izinlere sahip olduğunuzu kontrol edin.</p></translation>
+        <translation><p><nobr><b>%1</b></nobr> makine klasörü kaldırılamıyor.</p><p>Lütfen bu klasörün gerçekten var olduğunu ve kaldırmak için izinlere sahip olduğunuzu denetleyin.</p></translation>
     </message>
     <message>
         <source><p>Cannot create the machine folder <b>%1</b> in the parent folder <nobr><b>%2</b>.</nobr></p><p>This folder already exists and possibly belongs to another machine.</p></source>
@@ -9414,7 +9414,7 @@
     </message>
     <message>
         <source>You are about to create a new virtual machine without a hard drive. You will not be able to install an operating system on the machine until you add one. In the mean time you will only be able to start the machine using a virtual optical disk or from the network.</source>
-        <translation type="obsolete">Sabit sürücü olmayan yeni bir sanal makine oluşturmak üzeresiniz. Bir tane ekleyene kadar makine üzerine bir işletim sistemi yükleyemeyeceksiniz. Bu arada sadece sanal optik diski kullanarak veya ağdan makineyi başlatabileceksiniz.</translation>
+        <translation type="obsolete">Sabit sürücü olmayan yeni bir sanal makine oluşturmak üzeresiniz. Bir tane ekleyene kadar makine üzerine bir işletim sistemi yükleyemeyeceksiniz. Bu arada yalnızca sanal optik diski kullanarak veya ağdan makineyi başlatabileceksiniz.</translation>
     </message>
     <message>
         <source>Failed to drop data.</source>
@@ -9442,11 +9442,11 @@
     </message>
     <message>
         <source><p>You are trying to move machine <nobr><b>%1</b></nobr> to group <nobr><b>%2</b></nobr> which already have sub-group <nobr><b>%1</b></nobr>.</p><p>Please resolve this name-conflict and try again.</p></source>
-        <translation><p><nobr><b>%1</b></nobr> makinesini, <nobr><b>%1</b></nobr> alt grubuna zaten sahip <nobr><b>%2</b></nobr> grubuna taşımayı deniyorsunuz.</p><p>Lütfen bu isim çakışmasını çözün ve tekrar deneyin.</p></translation>
+        <translation><p><nobr><b>%1</b></nobr> makinesini, <nobr><b>%1</b></nobr> alt grubuna zaten sahip <nobr><b>%2</b></nobr> grubuna taşımayı deniyorsunuz.</p><p>Lütfen bu isim çakışmasını çözün ve yeniden deneyin.</p></translation>
     </message>
     <message>
         <source><p>You are trying to move group <nobr><b>%1</b></nobr> to group <nobr><b>%2</b></nobr> which already have another item with the same name.</p><p>Would you like to automatically rename it?</p></source>
-        <translation><p>Zaten aynı isimle olan başka bir öğeye sahip <nobr><b>%1</b></nobr> grubunu <nobr><b>%2</b></nobr> grubuna taşımayı deniyorsunuz.</p><p>Otomatik olarak yeniden adlandırmak ister misiniz?</p></translation>
+        <translation><p>Zaten aynı isimle olan başka bir ögeye sahip <nobr><b>%1</b></nobr> grubunu <nobr><b>%2</b></nobr> grubuna taşımayı deniyorsunuz.</p><p>Kendiliğinden yeniden adlandırmak ister misiniz?</p></translation>
     </message>
     <message>
         <source>Rename</source>
@@ -9685,7 +9685,7 @@
     </message>
     <message>
         <source>Do not show this message again</source>
-        <translation>Bu iletiyi tekrar gösterme</translation>
+        <translation>Bu iletiyi yeniden gösterme</translation>
     </message>
     <message>
         <source><p>Do you want to remove the NAT network <nobr><b>%1</b>?</nobr></p><p>If this network is in use by one or more virtual machine network adapters these adapters will no longer be usable until you correct their settings by either choosing a different network name or a different adapter attachment type.</p></source>
@@ -9838,7 +9838,7 @@
     </message>
     <message>
         <source><p>One or more disk image files are not currently accessible. As a result, you will not be able to operate virtual machines that use these files until they become accessible later.</p><p>Press <b>Check</b> to open the Virtual Media Manager window and see which files are inaccessible, or press <b>Ignore</b> to ignore this message.</p></source>
-        <translation><p>Bir ya da daha fazla disk kalıbı dosyaları şu anda erişilebilir değil. Sonuç olarak, daha sonra erişilebilir olana kadar bu dosyaları kullanan sanal makineleri işletemeyceksiniz.</p><p>Sanal Ortam Yöneticisi penceresini açmak için <b>Kontrol et</b> düğmesine basın ve hangi dosyaların erişilemez olduğunu görün, ya da bu mesajı yoksaymak için <b>Yoksay</b> düğmesine basın.</p></translation>
+        <translation><p>Bir ya da daha fazla disk kalıbı dosyaları şu anda erişilebilir değil. Sonuç olarak, daha sonra erişilebilir olana kadar bu dosyaları kullanan sanal makineleri işletemeyceksiniz.</p><p>Sanal Ortam Yöneticisi penceresini açmak için <b>Denetle/b> düğmesine basın ve hangi dosyaların erişilemez olduğunu görün, ya da bu iletiyi yoksaymak için <b>Yoksay</b> düğmesine basın.</p></translation>
     </message>
     <message>
         <source><p>Deleting the snapshot will cause the state information saved in it to be lost, and storage data spread over several image files that VirtualBox has created together with the snapshot will be merged into one file. This can be a lengthy process, and the information in the snapshot cannot be recovered.</p></p>Are you sure you want to delete the selected snapshot <b>%1</b>?</p></source>
@@ -9846,7 +9846,7 @@
     </message>
     <message>
         <source><p>Deleting the snapshot %1 will temporarily need more storage space. In the worst case the size of image %2 will grow by %3, however on this filesystem there is only %4 free.</p><p>Running out of storage space during the merge operation can result in corruption of the image and the VM configuration, i.e. loss of the VM and its data.</p><p>You may continue with deleting the snapshot at your own risk.</p></source>
-        <translation><p>%1 anlık görüntüsünü silmek geçici olarak daha fazla depolama alanı gerektirecek. En kötü durumda %2 kalıbının boyutu %3 kadar büyüyecek ancak bu dosya sisteminde sadece %4 boşluk var.</p><p>Birleştirme işlemi sırasında yetersiz disk alanında çalışmak VM yapılandırmasının ve kalıbın bozulmasıyla sunuçlanabilir, yani VM'in ve verisinin kaybolması.</p><p>Riski size ait olan anlık görüntüyü silerek devam edebilirsiniz.</p></tr [...]
+        <translation><p>%1 anlık görüntüsünü silmek geçici olarak daha fazla depolama alanı gerektirecek. En kötü durumda %2 kalıbının boyutu %3 kadar büyüyecek ancak bu dosya sisteminde yalnızca %4 boşluk var.</p><p>Birleştirme işlemi sırasında yetersiz disk alanında çalışmak VM yapılandırmasının ve kalıbın bozulmasıyla sunuçlanabilir, yani VM'in ve verisinin kaybolması.</p><p>Riski size ait olan anlık görüntüyü silerek devam edebilirsiniz.</p></ [...]
     </message>
     <message>
         <source><p>Are you sure you want to release the disk image file <nobr><b>%1</b></nobr>?</p><p>This will detach it from the following virtual machine(s): <b>%2</b>.</p></source>
@@ -9854,7 +9854,7 @@
     </message>
     <message>
         <source><p>Do you want to delete the storage unit of the virtual hard disk <nobr><b>%1</b></nobr>?</p><p>If you select <b>Delete</b> then the specified storage unit will be permanently deleted. This operation <b>cannot be undone</b>.</p><p>If you select <b>Keep</b> then the hard disk will be only removed from the list of known hard disks, but the storage unit will be left untouched which mak [...]
-        <translation><p><nobr><b>%1</b></nobr> sanal sabit diskinin depolama birimini silmek istediğinize emin misiniz?</p><p>Eğer <b>Sil</b>'i seçerseniz sonrasında belirtilmiş depolama birimi kalıcı olarak silinecektir. Bu işlem <b>geri alınamaz</b>.</p><p>Eğer <b>Tut</b>'u seçerseniz o zaman sabit disk sadece bilinen sabit diskler listesinden kaldırılacaktır ama daha sonra tekrar bu sab [...]
+        <translation><p><nobr><b>%1</b></nobr> sanal sabit diskinin depolama birimini silmek istediğinize emin misiniz?</p><p>Eğer <b>Sil</b>'i seçerseniz sonrasında belirtilmiş depolama birimi kalıcı olarak silinecektir. Bu işlem <b>geri alınamaz</b>.</p><p>Eğer <b>Tut</b>'u seçerseniz o zaman sabit disk yalnızca bilinen sabit diskler listesinden kaldırılacaktır ama daha sonra yeniden bu  [...]
     </message>
     <message>
         <source>Failed to open the disk image file <nobr><b>%1</b></nobr>.</source>
@@ -9866,7 +9866,7 @@
     </message>
     <message>
         <source>You are about to create a new virtual machine without a hard disk. You will not be able to install an operating system on the machine until you add one. In the mean time you will only be able to start the machine using a virtual optical disk or from the network.</source>
-        <translation>Sabit diski olmayan yeni bir sanal makine oluşturmak üzeresiniz. Bir tane ekleyene kadar makine üzerine bir işletim sistemi yükleyemeyeceksiniz. Bu arada sadece sanal optik diski kullanarak veya ağdan makineyi başlatabileceksiniz.</translation>
+        <translation>Sabit diski olmayan yeni bir sanal makine oluşturmak üzeresiniz. Bir tane ekleyene kadar makine üzerine bir işletim sistemi yükleyemeyeceksiniz. Bu arada yalnızca sanal optik diski kullanarak veya ağdan makineyi başlatabileceksiniz.</translation>
     </message>
     <message>
         <source><p>The virtual machine window will be now switched to <b>full-screen</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in full-screen mode. You can access it by pressing <b>Host+Home</b>.</p></source>
@@ -9893,17 +9893,21 @@
         <translation><p>VirtualBox COM nesnesini alma başarısız.</p><p>Uygulama şimdi sonlandırılacak.</p></translation>
     </message>
     <message>
-        <source>Delete</source>
-        <comment>extension pack</comment>
-        <translation type="unfinished">Sil</translation>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation><p>Bu hatanın nedeni büyük ihtimalle bir kurulum sorunundan dolayı IPC arka plan programı soketinin yanlış izinleridir. Lütfen <font color=blue>'/tmp'</font> ve <font color=blue>'/tmp/.vbox-*-ipc/'</font> için izinleri denetleyin</p></translation>
     </message>
     <message>
         <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <translation>İndirilmiş <nobr><b>%1</b></nobr> dosyasını silmek istiyor musunuz?</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <comment>extension pack</comment>
+        <translation>Sil</translation>
     </message>
     <message>
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
-        <translation type="unfinished"></translation>
+        <translation>Aşağıda listelenen <nobr><b>%1</b></nobr> dosyalarını silmek istiyor musunuz?</translation>
     </message>
 </context>
 <context>
@@ -9997,7 +10001,7 @@
     </message>
     <message>
         <source>There are no active network operations.</source>
-        <translation>Aktif ağ işlemleri yok.</translation>
+        <translation>Etkin ağ işlemleri yok.</translation>
     </message>
     <message>
         <source>&Cancel All</source>
@@ -10005,7 +10009,7 @@
     </message>
     <message>
         <source>Cancel all active network operations</source>
-        <translation>Tüm aktif ağ işlemlerini iptal et</translation>
+        <translation>Tüm etkin ağ işlemlerini iptal et</translation>
     </message>
     <message>
         <source>Error: %1.</source>
@@ -10072,7 +10076,7 @@
     </message>
     <message>
         <source>Unknown reason</source>
-        <translation>Bilinmeyen sebep</translation>
+        <translation>Bilinmeyen neden</translation>
     </message>
     <message>
         <source>%1: %2</source>
@@ -10093,7 +10097,7 @@
     </message>
     <message>
         <source>Proxy not found</source>
-        <translation>Proksi bulunamadı</translation>
+        <translation>Vekil bulunamadı</translation>
     </message>
     <message>
         <source>Url not found on the server</source>
@@ -10104,7 +10108,7 @@
     <name>UINetworkReplyPrivateThread</name>
     <message>
         <source>During proxy configuration</source>
-        <translation>Proksi yapılandırması sırasında</translation>
+        <translation>Vekil yapılandırması sırasında</translation>
     </message>
     <message>
         <source>During certificate downloading</source>
@@ -10881,7 +10885,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     <name>UISettingsDialog</name>
     <message>
         <source><i>Select a settings category from the list on the left-hand side and move the mouse over a settings item to get more information.</i></source>
-        <translation><i>Sol tarafınızdaki listeden bir ayar kategorisi seçin ve daha fazla bilgi almak için bir ayar öğesi üzerinde fareyi haraket ettirin.</i></translation>
+        <translation><i>Sol tarafınızdaki listeden bir ayar kategorisi seçin ve daha fazla bilgi almak için bir ayar ögesi üzerinde fareyi haraket ettirin.</i></translation>
     </message>
     <message>
         <source>On the <b>%1</b> page, %2</source>
@@ -10944,7 +10948,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Proxy</source>
-        <translation>Proksi</translation>
+        <translation>Vekil</translation>
     </message>
     <message>
         <source>Display</source>
@@ -11153,7 +11157,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     <name>UIUpdateStepVirtualBox</name>
     <message>
         <source>Checking for a new VirtualBox version...</source>
-        <translation>Yeni bir VirtualBox sürümü kontrol ediliyor...</translation>
+        <translation>Yeni bir VirtualBox sürümü denetleniyor...</translation>
     </message>
 </context>
 <context>
@@ -11184,7 +11188,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>Turns off the virtual machine.</p><p>Note that this action will stop machine execution immediately so that the guest operating system running inside it will not be able to perform a clean shutdown procedure which may result in <i>data loss</i> inside the virtual machine. Selecting this action is recommended only if the virtual machine does not respond to the <b>Send the shutdown signal</b> action.</p></source>
-        <translation><p>Sanal makineyi kapatır.</p><p>Bu eylem sanal makinenin çalıştırılmasını anında durduracak onun için içerisinde çalışan misafir işletim sisteminin, sanal makine içerisinde <i>veri kaybı</i> ile sonuçlanabilen temiz bir kapama işlemi yapılamayacağını unutmayın. Bu eylemi seçmek sadece eğer sanal makine <b>Kapama sinyali gönder</b> eylemine yanıt vermiyorsa önerilir.</p></translation>
+        <translation><p>Sanal makineyi kapatır.</p><p>Bu eylem sanal makinenin çalıştırılmasını anında durduracak onun için içerisinde çalışan misafir işletim sisteminin, sanal makine içerisinde <i>veri kaybı</i> ile sonuçlanabilen temiz bir kapama işlemi yapılamayacağını unutmayın. Bu eylemi seçmek yalnızca eğer sanal makine <b>Kapama sinyali gönder</b> eylemine yanıt vermiyorsa önerilir.</p></translation>
     </message>
     <message>
         <source>&Power off the machine</source>
@@ -11196,7 +11200,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>When checked, the machine will be returned to the state stored in the current snapshot after it is turned off. This is useful if you are sure that you want to discard the results of your last sessions and start again at that snapshot.</p></source>
-        <translation><p>İşaretlendiğinde, makine, kapatılıdıktan sonra şu anki anlık görüntüde depolanan duruma geri döndürülecektir. Bu, eğer son oturumunuzun sonuçlarından vazgeçmek ve bu anlık görüntüden tekrar başlatmak istediğinizden emin seniz faydalıdır.</p></translation>
+        <translation><p>İşaretlendiğinde, makine, kapatılıdıktan sonra şu anki anlık görüntüde depolanan duruma geri döndürülecektir. Bu, eğer son oturumunuzun sonuçlarından vazgeçmek ve bu anlık görüntüden yeniden başlatmak istediğinizden emin seniz faydalıdır.</p></translation>
     </message>
     <message>
         <source>&Restore current snapshot '%1'</source>
@@ -11637,7 +11641,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>A <b>dynamically allocated</b> hard drive file will only use space on your physical hard drive as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
-        <translation type="obsolete"><p><b>Değişken olarak ayrılan</b> sabit sürücü dosyası sadece fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında otomatik olarak tekrar küçülmeyecektir.</p></translation>
+        <translation type="obsolete"><p><b>Değişken olarak ayrılan</b> sabit sürücü dosyası yalnızca fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında kendiliğinden tekrar küçülmeyecektir.</p></translation>
     </message>
     <message>
         <source><p>A <b>fixed size</b> hard drive file may take longer to create on some systems but is often faster to use.</p></source>
@@ -11726,7 +11730,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>A <b>dynamically allocated</b> hard disk file will only use space on your physical hard disk as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
-        <translation><p><b>Değişken olarak ayrılan</b> sabit disk dosyası sadece fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında otomatik olarak tekrar küçülmeyecektir.</p></translation>
+        <translation><p><b>Değişken olarak ayrılan</b> sabit disk dosyası yalnızca fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında kendiliğinden yeniden küçülmeyecektir.</p></translation>
     </message>
     <message>
         <source><p>A <b>fixed size</b> hard disk file may take longer to create on some systems but is often faster to use.</p></source>
@@ -11872,7 +11876,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     <name>UIWizardExportApp</name>
     <message>
         <source>Checking files ...</source>
-        <translation>Dosyalar kontrol ediliyor...</translation>
+        <translation>Dosyalar denetleniyor...</translation>
     </message>
     <message>
         <source>Removing files ...</source>
@@ -11880,11 +11884,11 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Exporting Appliance ...</source>
-        <translation>Cihaz dışa aktarılıyor...</translation>
+        <translation>Aygıt dışa aktarılıyor...</translation>
     </message>
     <message>
         <source>Export Virtual Appliance</source>
-        <translation>Sanal Cihazı Dışa Aktar</translation>
+        <translation>Sanal Aygıtı Dışa Aktar</translation>
     </message>
     <message>
         <source>Restore Defaults</source>
@@ -11900,15 +11904,15 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>Please select the virtual machines that should be added to the appliance. You can select more than one. Please note that these machines have to be turned off before they can be exported.</p></source>
-        <translation><p>Lütfen cihaza eklenmesi gereken sanal makineleri seçin. Birden fazla seçebilirsiniz. Lütfen bu makinelerin dışa aktarılabilir olmadan önce kapalı olmak zorunda olduklarını unutmayın.</p></translation>
+        <translation><p>Lütfen aygıta eklenmesi gereken sanal makineleri seçin. Birden fazla seçebilirsiniz. Lütfen bu makinelerin dışa aktarılabilir olmadan önce kapalı olmak zorunda olduklarını unutmayın.</p></translation>
     </message>
     <message>
         <source>Appliance settings</source>
-        <translation>Cihaz ayarları</translation>
+        <translation>Aygıt ayarları</translation>
     </message>
     <message>
         <source>Please choose where to create the virtual appliance. You can create it on your own computer, on the Sun Cloud service or on an S3 storage server.</source>
-        <translation>Lütfen sanal cihazın nereye oluşturulacağını seçin. Kendi bilgisayarınıza, Sun Bulut hizmetine veya bir S3 depolama sunucusuna oluşturabilirsiniz.</translation>
+        <translation>Lütfen sanal aygıtın nereye oluşturulacağını seçin. Kendi bilgisayarınıza, Sun Bulut hizmetine veya bir S3 depolama sunucusuna oluşturabilirsiniz.</translation>
     </message>
     <message>
         <source>Create on</source>
@@ -11928,7 +11932,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Appliance</source>
-        <translation>Cihaz</translation>
+        <translation>Aygıt</translation>
     </message>
     <message>
         <source>&Username:</source>
@@ -11952,7 +11956,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Please choose a virtual appliance file</source>
-        <translation type="obsolete">Lütfen bir sanal cihaz dosyası seçin</translation>
+        <translation type="obsolete">Lütfen bir sanal aygıt dosyası seçin</translation>
     </message>
     <message>
         <source>Open Virtualization Format Archive (%1)</source>
@@ -11972,7 +11976,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Create a Manifest file for automatic data integrity checks on import.</source>
-        <translation>İçe aktarmada otomatik veri bütünlüğü kontrolleri için Manifest dosyası oluştur.</translation>
+        <translation>İçe aktarmada kendiliğinden veri bütünlüğü denetimi için Manifest dosyası oluştur.</translation>
     </message>
     <message>
         <source>Write &Manifest file</source>
@@ -11980,7 +11984,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>This is the descriptive information which will be added to the virtual appliance.  You can change it by double clicking on individual lines.</source>
-        <translation>Bu, sanal cihaza eklenecek olan tanımlayıcı bilgidir. Birbirinden ayrı satırlara çift tıklayarak değiştirebilirsiniz.</translation>
+        <translation>Bu, sanal aygıta eklenecek olan tanımlayıcı bilgidir. Birbirinden ayrı satırlara çift tıklayarak değiştirebilirsiniz.</translation>
     </message>
     <message>
         <source>Virtual &machines to export</source>
@@ -11988,7 +11992,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Appliance &settings</source>
-        <translation>Cihaz &ayarları</translation>
+        <translation>Aygıt &ayarları</translation>
     </message>
     <message>
         <source>&Destination</source>
@@ -12004,7 +12008,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Please choose a file to export the virtual appliance to</source>
-        <translation>Lütfen sanal cihazı dışa aktarmak için bir dosya seçin</translation>
+        <translation>Lütfen sanal aygıtı dışa aktarmak için bir dosya seçin</translation>
     </message>
     <message>
         <source>F&ormat:</source>
@@ -12051,14 +12055,14 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Choose a file to export the virtual appliance to...</source>
-        <translation>Lütfen sanal cihazı dışa aktarmak için bir dosya seçin...</translation>
+        <translation>Lütfen sanal aygıtı dışa aktarmak için bir dosya seçin...</translation>
     </message>
 </context>
 <context>
     <name>UIWizardExportAppPageExpert</name>
     <message>
         <source>Choose a file to export the virtual appliance to...</source>
-        <translation>Lütfen sanal cihazı dışa aktarmak için bir dosya seçin...</translation>
+        <translation>Lütfen sanal aygıtı dışa aktarmak için bir dosya seçin...</translation>
     </message>
 </context>
 <context>
@@ -12073,7 +12077,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from and should contain the operating system you wish to install on the virtual machine if you want to do that now. The disk will be ejected from the virtual drive automatically next time you switch the virtual machine off, but you can also do this yourself if needed u [...]
-        <translation><p>Lütfen sanal bir optik disk dosyası veya yeni sanal makinenizi ondan başlatmak için bir disk içeren fiziksel optik disk sürücüsü seçin.</p><p>Disk bir bilgisayarı başlatması için uygun olmalı ve sanal makineye yüklemeyi hemen yapmak istiyorsanız istediğiniz işletim sistemini içermeli. Disk bir dahaki sefere sanal makineyi kapattığınızda otomatik olarak sanal sürücüden çıkartılacaktır, ama aynı zamanda Aygıtlar menüsünü kullanmanız gerekirsede bun [...]
+        <translation><p>Lütfen sanal bir optik disk dosyası veya yeni sanal makinenizi ondan başlatmak için bir disk içeren fiziksel optik disk sürücüsü seçin.</p><p>Disk bir bilgisayarı başlatması için uygun olmalı ve sanal makineye yüklemeyi hemen yapmak istiyorsanız istediğiniz işletim sistemini içermeli. Disk bir dahaki sefere sanal makineyi kapattığınızda kendiliğinden sanal sürücüden çıkartılacaktır, ama aynı zamanda Aygıtlar menüsünü kullanmanız gerekirsede bunu  [...]
     </message>
     <message>
         <source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from. As this virtual machine has no hard drive you will not be able to install an operating system on it at the moment.</p></source>
@@ -12088,7 +12092,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     <name>UIWizardImportApp</name>
     <message>
         <source>Import Virtual Applicance</source>
-        <translation type="obsolete">Sanal Cihazı İçe Aktar</translation>
+        <translation type="obsolete">Sanal Aygıtı İçe Aktar</translation>
     </message>
     <message>
         <source>Restore Defaults</source>
@@ -12100,19 +12104,19 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Appliance to import</source>
-        <translation>İçe aktarmak için cihaz</translation>
+        <translation>İçe aktarmak için aygıt</translation>
     </message>
     <message>
         <source><p>VirtualBox currently supports importing appliances saved in the Open Virtualization Format (OVF). To continue, select the file to import below.</p></source>
-        <translation><p>VirtualBox şu anda Açık Sanallaştırma Biçimi (OVF) olarak kaydedilmiş cihazları içe aktarmayı destekler. Devam etmek için aşağıdan içe aktarma dosyasını seçin.</p></translation>
+        <translation><p>VirtualBox şu anda Açık Sanallaştırma Biçimi (OVF) olarak kaydedilmiş aygıtları içe aktarmayı destekler. Devam etmek için aşağıdan içe aktarma dosyasını seçin.</p></translation>
     </message>
     <message>
         <source>Open appliance...</source>
-        <translation type="obsolete">Cihaz aç...</translation>
+        <translation type="obsolete">Aygıt aç...</translation>
     </message>
     <message>
         <source>Select an appliance to import</source>
-        <translation type="obsolete">İçe aktarmak için bir cihaz seçin</translation>
+        <translation type="obsolete">İçe aktarmak için bir aygıt seçin</translation>
     </message>
     <message>
         <source>Open Virtualization Format (%1)</source>
@@ -12120,35 +12124,35 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source>Appliance settings</source>
-        <translation>Cihaz ayarları</translation>
+        <translation>Aygıt ayarları</translation>
     </message>
     <message>
         <source>These are the virtual machines contained in the appliance and the suggested settings of the imported VirtualBox machines. You can change many of the properties shown by double-clicking on the items and disable others using the check boxes below.</source>
-        <translation>Bunlar cihaz içinde bulunan sanal makineler ve içe aktarılmış VirtualBox makinelerinin önerilen ayarlarıdır. Öğelere çift tıklandığında gösterilen çoğu özellikleri değiştirebilirsiniz ve aşağıdan işaretleme kutularını kullanarak diğerlerini etkisizleştirebilirsiniz.</translation>
+        <translation>Bunlar aygıt içinde bulunan sanal makineler ve içe aktarılmış VirtualBox makinelerinin önerilen ayarlarıdır. Ögelere çift tıklandığında gösterilen çoğu özellikleri değiştirebilirsiniz ve aşağıdan işaretleme kutularını kullanarak diğerlerini etkisizleştirebilirsiniz.</translation>
     </message>
     <message>
         <source>Import Virtual Appliance</source>
-        <translation>Sanal Cihazı İçe Aktar</translation>
+        <translation>Sanal Aygıtı İçe Aktar</translation>
     </message>
     <message>
         <source>Choose a virtual appliance file to import...</source>
-        <translation>İçe aktarmak için bir sanal cihaz dosyası seçin...</translation>
+        <translation>İçe aktarmak için bir sanal aygıt dosyası seçin...</translation>
     </message>
     <message>
         <source>Please choose a virtual appliance file to import</source>
-        <translation>Lütfen içe aktarmak için bir sanal cihaz dosyası seçin</translation>
+        <translation>Lütfen içe aktarmak için bir sanal aygıt dosyası seçin</translation>
     </message>
     <message>
         <source>Appliance is not signed</source>
-        <translation>Cihaz imzalı değil</translation>
+        <translation>Aygıt imzalı değil</translation>
     </message>
     <message>
         <source>Appliance signed by %1 (trusted)</source>
-        <translation>Cihaz %1 tarafından imzalı (güvenilir)</translation>
+        <translation>Aygıt %1 tarafından imzalı (güvenilir)</translation>
     </message>
     <message>
         <source>Appliance signed by %1 (expired!)</source>
-        <translation>Cihaz %1 tarafından imzalı (süresi dolmuş!)</translation>
+        <translation>Aygıt %1 tarafından imzalı (süresi dolmuş!)</translation>
     </message>
     <message>
         <source>Unverified signature by %1!</source>
@@ -12195,7 +12199,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>A <b>dynamically allocated</b> hard drive file will only use space on your physical hard drive as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
-        <translation type="obsolete"><p><b>Değişken olarak ayrılan</b> sabit sürücü dosyası sadece fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında otomatik olarak tekrar küçülmeyecektir.</p></translation>
+        <translation type="obsolete"><p><b>Değişken olarak ayrılan</b> sabit sürücü dosyası yalnızca fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında kendiliğinden tekrar küçülmeyecektir.</p></translation>
     </message>
     <message>
         <source><p>A <b>fixed size</b> hard drive file may take longer to create on some systems but is often faster to use.</p></source>
@@ -12271,7 +12275,7 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
     </message>
     <message>
         <source><p>A <b>dynamically allocated</b> hard disk file will only use space on your physical hard disk as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
-        <translation><p><b>Değişken olarak ayrılan</b> sabit disk dosyası sadece fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında otomatik olarak tekrar küçülmeyecektir.</p></translation>
+        <translation><p><b>Değişken olarak ayrılan</b> sabit disk dosyası yalnızca fiziksel sabit sürücünüzdeki alanı doldurarak (en fazla <b>sabitlenmiş boyuta</b> kadar) kullanacak olmasına rağmen alan serbest kaldığında kendiliğinden yeniden küçülmeyecektir.</p></translation>
     </message>
     <message>
         <source><p>A <b>fixed size</b> hard disk file may take longer to create on some systems but is often faster to use.</p></source>
@@ -12627,15 +12631,15 @@ Version %1</source>
     <message>
         <source>Auto-resize Guest Display</source>
         <comment>enable/disable...</comment>
-        <translation type="obsolete">Misafir Ekranı Otomatik olarak Yeniden Boyutlandır</translation>
+        <translation type="obsolete">Misafir Ekranı Kendiliğinden Yeniden Boyutlandır</translation>
     </message>
     <message>
         <source>Auto-resize &Guest Display</source>
-        <translation type="obsolete">Misafir E&kranı Otomatik olarak Yeniden Boyutlandır</translation>
+        <translation type="obsolete">Misafir E&kranı Kendiliğinden Yeniden Boyutlandır</translation>
     </message>
     <message>
         <source>Automatically resize the guest display when the window is resized (requires Guest Additions)</source>
-        <translation type="obsolete">Pencere yeniden boyutlandırıldığında misafir ekranını otomatik olarak boyutlandır (Misafir Eklentilerini gerektirir)</translation>
+        <translation type="obsolete">Pencere yeniden boyutlandırıldığında misafir ekranını kendiliğinden boyutlandır (Misafir Eklentilerini gerektirir)</translation>
     </message>
     <message>
         <source>&Adjust Window Size</source>
@@ -13046,7 +13050,7 @@ Version %1</source>
     </message>
     <message>
         <source>No supported devices connected to the host PC</source>
-        <translation type="obsolete">Sunucu makineye desteklenen bir cihaz bağlanmamış</translation>
+        <translation type="obsolete">Sunucu makineye desteklenen bir aygıt bağlanmamış</translation>
     </message>
 </context>
 <context>
@@ -13378,7 +13382,7 @@ Version %1</source>
     </message>
     <message>
         <source>The actual default path value will be displayed after accepting the changes and opening this window again.</source>
-        <translation type="vanished">Gerçek varsayılan yol değeri, değişiklikler kabul edildikten ve bu pencere tekrar açıldıktan sonra görüntülenecektir.</translation>
+        <translation type="vanished">Gerçek varsayılan yol değeri, değişiklikler kabul edildikten ve bu pencere yeniden açıldıktan sonra görüntülenecektir.</translation>
     </message>
     <message>
         <source>Displays a window to select a different folder.</source>
@@ -13440,11 +13444,11 @@ Version %1</source>
     </message>
     <message>
         <source>When checked, the keyboard is automatically captured every time the VM window is activated. When the keyboard is captured, all keystrokes (including system ones like Alt-Tab) are directed to the VM.</source>
-        <translation type="obsolete">Seçildiği zaman, Sanal Makine penceresi etkin duruma her geçirildiğinde klavye otomatik olarak yakalanır. Klavye yakalandığı zaman tüm sistem tuş kombinasyonları (alt+tab gibi olanlar da dahil ) Sanal Makineye yönlendirilir.</translation>
+        <translation type="obsolete">Seçildiği zaman, Sanal Makine penceresi etkin duruma her geçirildiğinde klavye kendiliğinden yakalanır. Klavye yakalandığı zaman tüm sistem tuş kombinasyonları (alt+tab gibi olanlar da dahil ) Sanal Makineye yönlendirilir.</translation>
     </message>
     <message>
         <source>&Auto Capture Keyboard</source>
-        <translation type="obsolete">&Klavyeyi Otomatik Yakala</translation>
+        <translation type="obsolete">&Klavyeyi Kendiliğinden Yakala</translation>
     </message>
 </context>
 <context>
@@ -14264,7 +14268,7 @@ Version %1</source>
     <message>
         <source>Checking...</source>
         <comment>medium</comment>
-        <translation>Kontrol ediliyor...</translation>
+        <translation>Denetleniyor...</translation>
     </message>
     <message>
         <source>Inaccessible</source>
@@ -14359,7 +14363,7 @@ Version %1</source>
     <message>
         <source>Host-only adapter, '%1'</source>
         <comment>details report (network)</comment>
-        <translation>Sadece-anamakine bağdaştırıcısı, '%1'</translation>
+        <translation>Yalnızca-anamakine bağdaştırıcısı, '%1'</translation>
     </message>
     <message>
         <source>Intel PRO/1000 MT Server (82545EM)</source>
@@ -14374,7 +14378,7 @@ Version %1</source>
     <message>
         <source>Host-only Adapter</source>
         <comment>NetworkAttachmentType</comment>
-        <translation>Sadece-Anamakine Bağdaştırıcısı</translation>
+        <translation>Yalnızca-Anamakine Bağdaştırıcısı</translation>
     </message>
     <message>
         <source><nobr>%1 MB</nobr></source>
@@ -14519,12 +14523,12 @@ Version %1</source>
     <message>
         <source><i>Checking accessibility...</i></source>
         <comment>medium</comment>
-        <translation><i>Erişebilirlik kontrol ediliyor...</i></translation>
+        <translation><i>Erişebilirlik denetleniyor...</i></translation>
     </message>
     <message>
         <source>Failed to check accessibility of disk image files.</source>
         <comment>medium</comment>
-        <translation>Disk kalıbı dosyalarının erişebilirliği kontrolü başarısız.</translation>
+        <translation>Disk kalıbı dosyalarının erişebilirliği denetimi başarısız.</translation>
     </message>
     <message>
         <source><b>No disk image file selected</b></source>
@@ -14552,7 +14556,7 @@ Version %1</source>
     <message>
         <source>Some of the files in this hard disk chain are inaccessible. Please use the Virtual Media Manager in <b>Show Differencing Hard Disks</b> mode to inspect these files.</source>
         <comment>medium</comment>
-        <translation type="obsolete">Bu sabit disk zincirindeki ortamın bazısı erişilemez. Lütfen bu ortamı incelemek için <b>Ayrımlanan Sabit Diskleri Göster</b> içindeki Sanal Ortam Yönetcisini kullanın.</translation>
+        <translation type="obsolete">Bu sabit disk zincirindeki ortamın bazısı erişilemez. Lütfen bu ortamı incelemek için <b>Ayrımlanan Sabit Diskleri Göster</b> içindeki Sanal Ortam Yöneticisini kullanın.</translation>
     </message>
     <message>
         <source>This base hard disk is indirectly attached using the following differencing hard disk:</source>
@@ -15173,7 +15177,7 @@ Version %1</source>
     <message>
         <source>Active</source>
         <comment>details report (VT-x/AMD-V)</comment>
-        <translation>Aktif</translation>
+        <translation>Etkin</translation>
     </message>
     <message>
         <source>Inactive</source>
@@ -15183,7 +15187,7 @@ Version %1</source>
     <message>
         <source>Active</source>
         <comment>details report (Nested Paging)</comment>
-        <translation>Aktif</translation>
+        <translation>Etkin</translation>
     </message>
     <message>
         <source>Inactive</source>
@@ -15193,7 +15197,7 @@ Version %1</source>
     <message>
         <source>Active</source>
         <comment>details report (Unrestricted Execution)</comment>
-        <translation>Aktif</translation>
+        <translation>Etkin</translation>
     </message>
     <message>
         <source>Inactive</source>
@@ -15257,7 +15261,7 @@ Version %1</source>
     <message>
         <source>Some of the files in this hard drive chain are inaccessible. Please use the Virtual Medium Manager to inspect these files.</source>
         <comment>medium</comment>
-        <translation type="obsolete">Bu sabit sürücü zincirindeki dosyaların bazıları erişilemez. Lütfen bu dosyaları incelemek için Sanal Ortam Yönetcisi'ni kullanın.</translation>
+        <translation type="obsolete">Bu sabit sürücü zincirindeki dosyaların bazıları erişilemez. Lütfen bu dosyaları incelemek için Sanal Ortam Yöneticisi'ni kullanın.</translation>
     </message>
     <message>
         <source>This base hard drive is indirectly attached using the following differencing hard drive:</source>
@@ -15280,7 +15284,7 @@ Version %1</source>
     <message>
         <source>Some of the files in this hard disk chain are inaccessible. Please use the Virtual Medium Manager to inspect these files.</source>
         <comment>medium</comment>
-        <translation>Bu sabit disk zincirindeki dosyaların bazıları erişilemez. Lütfen bu dosyaları incelemek için Sanal Ortam Yönetcisi'ni kullanın.</translation>
+        <translation>Bu sabit disk zincirindeki dosyaların bazıları erişilemez. Lütfen bu dosyaları incelemek için Sanal Ortam Yöneticisi'ni kullanın.</translation>
     </message>
     <message>
         <source>Please choose a location for new virtual hard disk file</source>
@@ -15431,7 +15435,7 @@ Version %1</source>
     </message>
     <message>
         <source><i>Select a settings category from the list on the left-hand side and move the mouse over a settings item to get more information<i>.</source>
-        <translation type="obsolete"><i>Sol taraftaki listeden bir ayar kategorisi seçin ve daha fazla bilgi almak için fareyi ayar öğelerinin  üzerine getirin</i>.</translation>
+        <translation type="obsolete"><i>Sol taraftaki listeden bir ayar kategorisi seçin ve daha fazla bilgi almak için fareyi ayar ögelerinin  üzerine getirin</i>.</translation>
     </message>
     <message>
         <source> General </source>
@@ -15495,7 +15499,7 @@ Version %1</source>
     </message>
     <message>
         <source>&Auto capture keyboard</source>
-        <translation type="obsolete">&Klavyeyi otomatik yakala</translation>
+        <translation type="obsolete">&Klavyeyi kendiliğinden yakala</translation>
     </message>
     <message>
         <source>&USB Device Filters</source>
@@ -15591,7 +15595,7 @@ Version %1</source>
     </message>
     <message>
         <source>Holds the key used as a Host Key in the VM window. Activate the entry field and press a new Host Key. Note that alphanumeric, cursor movement and editing keys cannot be used.</source>
-        <translation type="obsolete">VM penceresinde, kullanılan anahtarı, makine anahtarı olarak gösterir. Girdi alanını aktif hale getirin ve yeni bir makine anahtarına basın. alfa numerik... işaretci hareketi ve anahtar düzenlemesinin, makine anahtarı olarak kullanılamayacağını unutmayın.</translation>
+        <translation type="obsolete">VM penceresinde, kullanılan anahtarı, makine anahtarı olarak gösterir. Girdi alanını aktif hale getirin ve yeni bir makine anahtarına basın. alfa numerik... işaretçi hareketi ve anahtar düzenlemesinin, makine anahtarı olarak kullanılamayacağını unutmayın.</translation>
     </message>
     <message>
         <source>New Filter %1</source>
@@ -15684,7 +15688,7 @@ to the system default language.</qt>
     </message>
     <message>
         <source>When checked, the keyboard is automatically captured every time the VM window is activated. When the keyboard is captured, all keystrokes (including system ones like Alt-Tab) are directed to the VM.</source>
-        <translation type="obsolete">Seçildiği zaman, Sanal Makine penceresi aktif duruma geçirildiği her an klavye otomatik olarak yakalanır.Klavye yakalandığı zaman her bir system tuşu ki bunlar alt+tab gibi olanlar Sanal Makineye yönlendirilebilir.</translation>
+        <translation type="obsolete">Seçildiği zaman, Sanal Makine penceresi aktif duruma geçirildiği her an klavye kendiliğinden yakalanır.Klavye yakalandığı zaman her bir system tuşu ki bunlar alt+tab gibi olanlar Sanal Makineye yönlendirilebilir.</translation>
     </message>
     <message>
         <source>Lists all global USB filters. The checkbox to the left defines whether the particular filter is enabled or not.</source>
@@ -16052,7 +16056,7 @@ to the system default language.</qt>
     </message>
     <message>
         <source>Checking accessibility</source>
-        <translation>Erişilebilirlik kontrol ediliyor</translation>
+        <translation>Erişilebilirlik denetleniyor</translation>
     </message>
     <message>
         <source>&Select</source>
@@ -16280,7 +16284,7 @@ to the system default language.</qt>
     </message>
     <message>
         <source><p>Please fill out this registration form to let us know that you use VirtualBox and, optionally, to keep you informed about VirtualBox news and updates.</p><p>Enter your full name using Latin characters and your e-mail address to the fields below. Please note that innotek will use this information only to gather product usage statistics and to send you VirtualBox newsletters. In particular, innotek will never pass your data to third parties. Detailed in [...]
-        <translation type="obsolete"><p>Lütfen VirtualBox kullandığınızı öğrenebilmemiz ve sizi VirtualBox haberleri ve güncellemeleri gibi konularda bilgilendirebilmemiz için kayıt formunu doldurun.</p><p>Aşağıdaki alanlara Latin karakterlerini kullanarak tam adınızı ve e-posta adresinizi girin. Lütfen innotek'in bu bilgileri sadece ürün kullanımı istatistiklerini toplamak ve size VirtualBox ilgili haberleri göndermek için kullandığını unutmayın. Özellikle innotek [...]
+        <translation type="obsolete"><p>Lütfen VirtualBox kullandığınızı öğrenebilmemiz ve sizi VirtualBox haberleri ve güncellemeleri gibi konularda bilgilendirebilmemiz için kayıt formunu doldurun.</p><p>Aşağıdaki alanlara Latin karakterlerini kullanarak tam adınızı ve e-posta adresinizi girin. Lütfen innotek'in bu bilgileri yalnızca ürün kullanımı istatistiklerini toplamak ve size VirtualBox ilgili haberleri göndermek için kullandığını unutmayın. Özellikle innot [...]
     </message>
     <message>
         <source>&Name</source>
@@ -16328,7 +16332,7 @@ to the system default language.</qt>
     </message>
     <message>
         <source><p>Please fill out this registration form to let us know that you use VirtualBox and, optionally, to keep you informed about VirtualBox news and updates.</p><p>Enter your full name using Latin characters and your e-mail address to the fields below. Sun Microsystems will use this information only to gather product usage statistics and to send you VirtualBox newsletters. In particular, Sun Microsystems will never pass your data to third parties. Detailed i [...]
-        <translation type="obsolete"><p>Lütfen VirtualBox kullandığınızı öğrenebilmemiz ve sizi VirtualBox haberleri ve güncellemeleri gibi konularda bilgilendirebilmemiz için kayıt formunu doldurun.</p><p>Aşağıdaki alanlara Latin karakterlerini kullanarak tam adınızı ve e-posta adresinizi girin. Lütfen innotek'in bu bilgileri sadece ürün kullanımı istatistiklerini toplamak ve size VirtualBox ilgili haberleri göndermek için kullandığını unutmayın. Özellikle innotek [...]
+        <translation type="obsolete"><p>Lütfen VirtualBox kullandığınızı öğrenebilmemiz ve sizi VirtualBox haberleri ve güncellemeleri gibi konularda bilgilendirebilmemiz için kayıt formunu doldurun.</p><p>Aşağıdaki alanlara Latin karakterlerini kullanarak tam adınızı ve e-posta adresinizi girin. Lütfen innotek'in bu bilgileri yalnızca ürün kullanımı istatistiklerini toplamak ve size VirtualBox ilgili haberleri göndermek için kullandığını unutmayın. Özellikle innot [...]
     </message>
     <message>
         <source>Check this box if you do not want to receive mail from Sun Microsystems at the e-mail address specified above.</source>
@@ -16676,7 +16680,7 @@ to the system default language.</qt>
     <name>VBoxSettingsDialog</name>
     <message>
         <source><i>Select a settings category from the list on the left-hand side and move the mouse over a settings item to get more information</i>.</source>
-        <translation type="obsolete"><i>Sol taraftaki listeden bir ayar kategorisi seçin ve daha fazla bilgi almak için fareyi ayar öğelerinin  üzerine getirin</i>.</translation>
+        <translation type="obsolete"><i>Sol taraftaki listeden bir ayar kategorisi seçin ve daha fazla bilgi almak için fareyi ayar ögelerinin  üzerine getirin</i>.</translation>
     </message>
     <message>
         <source>Invalid settings detected</source>
@@ -17514,7 +17518,7 @@ eşleşebilir.</qt></translation>
     </message>
     <message>
         <source>Holds the IRQ number of this serial port. Valid values are integer numbers in range from <tt>0</tt> to <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> is enabled for this virtual machine.</source>
-        <translation type="obsolete">Seri portun IRQ numaralarını gösterir.  Geçerli değerler <tt>0</tt> ile <tt>255</tt> arasındaki tüm sayılardır. <tt>15</tt>'ten daha büyük sayılar sadece sanal makine için <b>I/O APIC</b> etkinleştirildiyse kullanılabilir.</translation>
+        <translation type="obsolete">Seri portun IRQ numaralarını gösterir.  Geçerli değerler <tt>0</tt> ile <tt>255</tt> arasındaki tüm sayılardır. <tt>15</tt>'ten daha büyük sayılar yalnızca sanal makine için <b>I/O APIC</b> etkinleştirildiyse kullanılabilir.</translation>
     </message>
     <message>
         <source>I/O Po&rt</source>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts
index d39fc8e..a0c4893 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts
@@ -10165,6 +10165,10 @@ p, li { white-space: pre-wrap; }
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetAdditions</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts
index 3cc18a7..50d2825 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts
@@ -5863,6 +5863,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniToolBar</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts
index f2befd3..c8e2c60 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts
@@ -9407,6 +9407,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniProcessWidgetUserManual</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts
index 0d30b11..a73800d 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts
@@ -5863,6 +5863,10 @@
         <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>UIMiniToolBar</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/qt_el.ts b/src/VBox/Frontends/VirtualBox/nls/qt_el.ts
index 1e64dab..a494b08 100644
--- a/src/VBox/Frontends/VirtualBox/nls/qt_el.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/qt_el.ts
@@ -29,6 +29,7 @@
     </message>
     <message>
         <source>About %1</source>
+        <translatorcomment>2016-11-10</translatorcomment>
         <translation>Πληροφορίες για το %1</translation>
     </message>
 </context>
@@ -218,19 +219,19 @@ have libgstreamer-plugins-base installed.</source>
     </message>
     <message>
         <source>&OK</source>
-        <translation>&Εντάξει</translation>
+        <translation>Εντάξει</translation>
     </message>
     <message>
         <source>Look &in:</source>
-        <translation>Ψάξε &in :</translation>
+        <translation>Ψάξε σε:</translation>
     </message>
     <message>
         <source>File &name:</source>
-        <translation>&Όνομα αρχεiου:</translation>
+        <translation>Όνομα αρχεiου:</translation>
     </message>
     <message>
         <source>File &type:</source>
-        <translation>&Τύπος αρχείου:</translation>
+        <translation>Τύπος αρχείου:</translation>
     </message>
     <message>
         <source>Back</source>
@@ -310,39 +311,39 @@ have libgstreamer-plugins-base installed.</source>
     </message>
     <message>
         <source>&Open</source>
-        <translation>&Άνοιγμα</translation>
+        <translation>Άνοιγμα</translation>
     </message>
     <message>
         <source>&Save</source>
-        <translation>&Αποθήκευση</translation>
+        <translation>Αποθήκευση</translation>
     </message>
     <message>
         <source>&Rename</source>
-        <translation>&Μετονομασία</translation>
+        <translation>Μετονομασία</translation>
     </message>
     <message>
         <source>&Delete</source>
-        <translation>&Διαγραφή</translation>
+        <translation>Διαγραφή</translation>
     </message>
     <message>
         <source>R&eload</source>
-        <translation>Φ&όρτωμα</translation>
+        <translation>Φόρτωμα</translation>
     </message>
     <message>
         <source>Sort by &Name</source>
-        <translation>Ταξινόμηση κατά &Όνομα</translation>
+        <translation>Ταξινόμηση κατά Όνομα</translation>
     </message>
     <message>
         <source>Sort by &Size</source>
-        <translation>Ταξινόμηση κατά &Μέγεθος</translation>
+        <translation>Ταξινόμηση κατά Μέγεθος</translation>
     </message>
     <message>
         <source>Sort by &Date</source>
-        <translation>Ταξινόμηση κατά &Ημερομηνία</translation>
+        <translation>Ταξινόμηση κατά Ημερομηνία</translation>
     </message>
     <message>
         <source>&Unsorted</source>
-        <translation>&Αταξινόμητα</translation>
+        <translation>Αταξινόμητα</translation>
     </message>
     <message>
         <source>Sort</source>
@@ -350,7 +351,7 @@ have libgstreamer-plugins-base installed.</source>
     </message>
     <message>
         <source>Show &hidden files</source>
-        <translation>Εμφάνιση &Κρυφών Αρχείων</translation>
+        <translation>Εμφάνιση κρυφών αρχείων</translation>
     </message>
     <message>
         <source>the file</source>
@@ -374,11 +375,11 @@ have libgstreamer-plugins-base installed.</source>
     </message>
     <message>
         <source>&Yes</source>
-        <translation>&Ναι</translation>
+        <translation>Ναι</translation>
     </message>
     <message>
         <source>&No</source>
-        <translation>&Όχι</translation>
+        <translation>Όχι</translation>
     </message>
     <message>
         <source>New Folder 1</source>
@@ -512,23 +513,23 @@ to
     <name>Q3TextEdit</name>
     <message>
         <source>&Undo</source>
-        <translation>&Αναίρεση</translation>
+        <translation>Αναίρεση</translation>
     </message>
     <message>
         <source>&Redo</source>
-        <translation>&Ακύρωση Αναίρεσης</translation>
+        <translation>Ακύρωση Αναίρεσης</translation>
     </message>
     <message>
         <source>Cu&t</source>
-        <translation>Αποκοπ&ή</translation>
+        <translation>Αποκοπή</translation>
     </message>
     <message>
         <source>&Copy</source>
-        <translation>&Αντιγραφή</translation>
+        <translation>Αντιγραφή</translation>
     </message>
     <message>
         <source>&Paste</source>
-        <translation>&Επικόλληση</translation>
+        <translation>Επικόλληση</translation>
     </message>
     <message>
         <source>Clear</source>
@@ -644,23 +645,23 @@ to
     <name>Q3Wizard</name>
     <message>
         <source>&Cancel</source>
-        <translation>&Άκυρο</translation>
+        <translation>Άκυρο</translation>
     </message>
     <message>
         <source>< &Back</source>
-        <translation>< &Πίσω</translation>
+        <translation>< Πίσω</translation>
     </message>
     <message>
         <source>&Next ></source>
-        <translation>&Επόμενο ></translation>
+        <translation>Επόμενο ></translation>
     </message>
     <message>
         <source>&Finish</source>
-        <translation>&Τέλος</translation>
+        <translation>Τέλος</translation>
     </message>
     <message>
         <source>&Help</source>
-        <translation>&Βοήθεια</translation>
+        <translation>Βοήθεια</translation>
     </message>
 </context>
 <context>
@@ -686,15 +687,15 @@ to
     <name>QAbstractSpinBox</name>
     <message>
         <source>&Step up</source>
-        <translation>&Βήμα πάνω</translation>
+        <translation>Βήμα πάνω</translation>
     </message>
     <message>
         <source>Step &down</source>
-        <translation>Βήμα &κάτω</translation>
+        <translation>Βήμα κάτω</translation>
     </message>
     <message>
         <source>&Select All</source>
-        <translation>&Επιλογή Όλων</translation>
+        <translation>Επιλογή Όλων</translation>
     </message>
 </context>
 <context>
@@ -740,43 +741,43 @@ to
     <name>QColorDialog</name>
     <message>
         <source>Hu&e:</source>
-        <translation>Απόχρωσ&η:</translation>
+        <translation>Απόχρωση:</translation>
     </message>
     <message>
         <source>&Sat:</source>
-        <translation>&Κορεσμός:</translation>
+        <translation>Κορεσμός:</translation>
     </message>
     <message>
         <source>&Val:</source>
-        <translation>&Φωτεινότητα:</translation>
+        <translation>Φωτεινότητα:</translation>
     </message>
     <message>
         <source>&Red:</source>
-        <translation>&Κόκκινο:</translation>
+        <translation>Κόκκινο:</translation>
     </message>
     <message>
         <source>&Green:</source>
-        <translation>&Πράσινο:</translation>
+        <translation>Πράσινο:</translation>
     </message>
     <message>
         <source>Bl&ue:</source>
-        <translation>Μπ&λε:</translation>
+        <translation>Μπλε:</translation>
     </message>
     <message>
         <source>A&lpha channel:</source>
-        <translation>Ά&λφα κανάλι:</translation>
+        <translation>Άλφα κανάλι:</translation>
     </message>
     <message>
         <source>&Basic colors</source>
-        <translation>&Βασικά χρώματα</translation>
+        <translation>Βασικά χρώματα</translation>
     </message>
     <message>
         <source>&Custom colors</source>
-        <translation>&Ειδικά χρώματα</translation>
+        <translation>Ειδικά χρώματα</translation>
     </message>
     <message>
         <source>&Add to Custom Colors</source>
-        <translation>&Πρόσθεση σε ειδικά χρώματα</translation>
+        <translation>Πρόσθεση σε ειδικά χρώματα</translation>
     </message>
     <message>
         <source>Select color</source>
@@ -980,19 +981,19 @@ to
     </message>
     <message>
         <source>&Yes</source>
-        <translation>&Ναι</translation>
+        <translation>Ναι</translation>
     </message>
     <message>
         <source>Yes to &All</source>
-        <translation>Ναι σε &Όλα</translation>
+        <translation>Ναι σε Όλα</translation>
     </message>
     <message>
         <source>&No</source>
-        <translation>&Όχι</translation>
+        <translation>Όχι</translation>
     </message>
     <message>
         <source>N&o to All</source>
-        <translation>Ό&χι σε Όλα</translation>
+        <translation>Όχι σε Όλα</translation>
     </message>
     <message>
         <source>Save All</source>
@@ -1020,7 +1021,7 @@ to
     </message>
     <message>
         <source>&OK</source>
-        <translation>&Ναι</translation>
+        <translation>Ναι</translation>
     </message>
 </context>
 <context>
@@ -1090,11 +1091,11 @@ to
     </message>
     <message>
         <source>&Show this message again</source>
-        <translation>&Προβολή αυτού του μηνύματος πάλι</translation>
+        <translation>Προβολή αυτού του μηνύματος πάλι</translation>
     </message>
     <message>
         <source>&OK</source>
-        <translation>&Ναι</translation>
+        <translation>Ναι</translation>
     </message>
 </context>
 <context>
@@ -1109,11 +1110,11 @@ to
     </message>
     <message>
         <source>&Open</source>
-        <translation>&Άνοιγμα</translation>
+        <translation>Άνοιγμα</translation>
     </message>
     <message>
         <source>&Save</source>
-        <translation>&Αποθήκευση</translation>
+        <translation>Αποθήκευση</translation>
     </message>
     <message>
         <source>Open</source>
@@ -1139,15 +1140,15 @@ Please verify the correct file name was given.</source>
     </message>
     <message>
         <source>&Rename</source>
-        <translation>&Μετονομασία</translation>
+        <translation>Μετονομασία</translation>
     </message>
     <message>
         <source>&Delete</source>
-        <translation>&Διαγραφή</translation>
+        <translation>Διαγραφή</translation>
     </message>
     <message>
         <source>Show &hidden files</source>
-        <translation>Εμφάνιση &κρυφών αρχείων</translation>
+        <translation>Εμφάνιση κρυφών αρχείων</translation>
     </message>
     <message>
         <source>Back</source>
@@ -1229,11 +1230,11 @@ Do you want to delete it anyway?</source>
     </message>
     <message>
         <source>&New Folder</source>
-        <translation>&Νέος Φάκελος</translation>
+        <translation>Νέος Φάκελος</translation>
     </message>
     <message>
         <source>&Choose</source>
-        <translation>&Επιλογή</translation>
+        <translation>Επιλογή</translation>
     </message>
     <message>
         <source>Remove</source>
@@ -1241,7 +1242,7 @@ Do you want to delete it anyway?</source>
     </message>
     <message>
         <source>File &name:</source>
-        <translation>Όνομα &αρχείου  :</translation>
+        <translation>Όνομα αρχείου  :</translation>
     </message>
     <message>
         <source>Look in:</source>
@@ -1484,15 +1485,15 @@ Do you want to delete it anyway?</source>
     <name>QFontDialog</name>
     <message>
         <source>&Font</source>
-        <translation>&Γραμματοσειρά</translation>
+        <translation>Γραμματοσειρά</translation>
     </message>
     <message>
         <source>Font st&yle</source>
-        <translation>Στυλ γρ&αμματοσειράς</translation>
+        <translation>Στυλ γραμματοσειράς</translation>
     </message>
     <message>
         <source>&Size</source>
-        <translation>&Μέγεθος</translation>
+        <translation>Μέγεθος</translation>
     </message>
     <message>
         <source>Effects</source>
@@ -1500,11 +1501,11 @@ Do you want to delete it anyway?</source>
     </message>
     <message>
         <source>Stri&keout</source>
-        <translation>Γρά&μμιση</translation>
+        <translation>Γράμμιση</translation>
     </message>
     <message>
         <source>&Underline</source>
-        <translation>&Υπογράμμιση</translation>
+        <translation>Υπογράμμιση</translation>
     </message>
     <message>
         <source>Sample</source>
@@ -1512,7 +1513,7 @@ Do you want to delete it anyway?</source>
     </message>
     <message>
         <source>Wr&iting System</source>
-        <translation>Σύ&στημα εγγραφής</translation>
+        <translation>Σύστημα εγγραφής</translation>
     </message>
     <message>
         <source>Select Font</source>
@@ -1939,23 +1940,23 @@ Do you want to delete it anyway?</source>
     <name>QLineEdit</name>
     <message>
         <source>&Undo</source>
-        <translation>&Αναίρεση</translation>
+        <translation>Αναίρεση</translation>
     </message>
     <message>
         <source>&Redo</source>
-        <translation>&Ακύρωση Αναίρεσης</translation>
+        <translation>Ακύρωση Αναίρεσης</translation>
     </message>
     <message>
         <source>Cu&t</source>
-        <translation>Αποκοπ&ή</translation>
+        <translation>Αποκοπή</translation>
     </message>
     <message>
         <source>&Copy</source>
-        <translation>&Αντιγραφή</translation>
+        <translation>Αντιγραφή</translation>
     </message>
     <message>
         <source>&Paste</source>
-        <translation>&Επικόλληση</translation>
+        <translation>Επικόλληση</translation>
     </message>
     <message>
         <source>Delete</source>
@@ -2125,31 +2126,31 @@ Do you want to delete it anyway?</source>
     </message>
     <message>
         <source>&Restore</source>
-        <translation>&Επαναφορά</translation>
+        <translation>Επαναφορά</translation>
     </message>
     <message>
         <source>&Move</source>
-        <translation>&Μετακίνηση</translation>
+        <translation>Μετακίνηση</translation>
     </message>
     <message>
         <source>&Size</source>
-        <translation>&Μέγεθος</translation>
+        <translation>Μέγεθος</translation>
     </message>
     <message>
         <source>Mi&nimize</source>
-        <translation>Ε&λαχιστοποίηση</translation>
+        <translation>Ελαχιστοποίηση</translation>
     </message>
     <message>
         <source>Ma&ximize</source>
-        <translation>Μ&εγιστοποίηση</translation>
+        <translation>Μεγιστοποίηση</translation>
     </message>
     <message>
         <source>Stay on &Top</source>
-        <translation>Παραμονή στην &επιφάνεια</translation>
+        <translation>Παραμονή στην επιφάνεια</translation>
     </message>
     <message>
         <source>&Close</source>
-        <translation>&Κλείσιμο</translation>
+        <translation>Κλείσιμο</translation>
     </message>
     <message>
         <source>- [%1]</source>
@@ -3084,7 +3085,7 @@ Please choose a different file name.</source>
     </message>
     <message>
         <source>&Name:</source>
-        <translation>&Όνομα:</translation>
+        <translation>Όνομα:</translation>
     </message>
     <message>
         <source>P&roperties</source>
@@ -3913,27 +3914,27 @@ Please choose a different file name.</source>
     <name>QTextControl</name>
     <message>
         <source>&Undo</source>
-        <translation>&Αναίρεση</translation>
+        <translation>Αναίρεση</translation>
     </message>
     <message>
         <source>&Redo</source>
-        <translation>&Ακύρωση Αναίρεσης</translation>
+        <translation>Ακύρωση Αναίρεσης</translation>
     </message>
     <message>
         <source>Cu&t</source>
-        <translation>Αποκοπ&ή</translation>
+        <translation>Αποκοπή</translation>
     </message>
     <message>
         <source>&Copy</source>
-        <translation>&Αντιγραφή</translation>
+        <translation>Αντιγραφή</translation>
     </message>
     <message>
         <source>Copy &Link Location</source>
-        <translation>Αντιγραφή &Θέσης Δεσμού</translation>
+        <translation>Αντιγραφή Θέσης Δεσμού</translation>
     </message>
     <message>
         <source>&Paste</source>
-        <translation>&Επικόλληση</translation>
+        <translation>Επικόλληση</translation>
     </message>
     <message>
         <source>Delete</source>
@@ -4358,11 +4359,11 @@ Please choose a different file name.</source>
     </message>
     <message>
         <source>< &Back</source>
-        <translation>< &Πίσω</translation>
+        <translation>< Πίσω</translation>
     </message>
     <message>
         <source>&Finish</source>
-        <translation>&Τέλος</translation>
+        <translation>Τέλος</translation>
     </message>
     <message>
         <source>Cancel</source>
@@ -4370,46 +4371,46 @@ Please choose a different file name.</source>
     </message>
     <message>
         <source>&Help</source>
-        <translation>&Βοήθεια</translation>
+        <translation>Βοήθεια</translation>
     </message>
     <message>
         <source>&Next</source>
-        <translation>&Επόμενο</translation>
+        <translation>Επόμενο</translation>
     </message>
     <message>
         <source>&Next ></source>
-        <translation>&Επόμενο ></translation>
+        <translation>Επόμενο ></translation>
     </message>
 </context>
 <context>
     <name>QWorkspace</name>
     <message>
         <source>&Restore</source>
-        <translation>&Επαναφορά</translation>
+        <translation>Επαναφορά</translation>
     </message>
     <message>
         <source>&Move</source>
-        <translation>&Μετακίνηση</translation>
+        <translation>Μετακίνηση</translation>
     </message>
     <message>
         <source>&Size</source>
-        <translation>&Μέγεθος</translation>
+        <translation>Μέγεθος</translation>
     </message>
     <message>
         <source>Mi&nimize</source>
-        <translation>Ε&λαχιστοποίηση</translation>
+        <translation>Ελαχιστοποίηση</translation>
     </message>
     <message>
         <source>Ma&ximize</source>
-        <translation>Μ&εγιστοποίηση</translation>
+        <translation>Μεγιστοποίηση</translation>
     </message>
     <message>
         <source>&Close</source>
-        <translation>&Κλείσιμο</translation>
+        <translation>Κλείσιμο</translation>
     </message>
     <message>
         <source>Stay on &Top</source>
-        <translation>Παραμονή στην &επιφάνεια</translation>
+        <translation>Παραμονή στην επιφάνεια</translation>
     </message>
     <message>
         <source>Sh&ade</source>
diff --git a/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendGlobal.cpp b/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendGlobal.cpp
index 83a1816..8d2a49a 100644
--- a/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendGlobal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendGlobal.cpp
@@ -668,17 +668,19 @@ template<> QString toInternalString(const UIExtraDataMetaDefs::RuntimeMenuInputA
     QString strResult;
     switch (runtimeMenuInputActionType)
     {
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_Keyboard:          strResult = "Keyboard"; break;
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_KeyboardSettings:  strResult = "KeyboardSettings"; break;
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCAD:           strResult = "TypeCAD"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_Keyboard:           strResult = "Keyboard"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_KeyboardSettings:   strResult = "KeyboardSettings"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCAD:            strResult = "TypeCAD"; break;
 #ifdef VBOX_WS_X11
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCABS:          strResult = "TypeCABS"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCABS:           strResult = "TypeCABS"; break;
 #endif /* VBOX_WS_X11 */
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCtrlBreak:     strResult = "TypeCtrlBreak"; break;
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeInsert:        strResult = "TypeInsert"; break;
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_Mouse:             strResult = "Mouse"; break;
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_MouseIntegration:  strResult = "MouseIntegration"; break;
-        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_All:               strResult = "All"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCtrlBreak:      strResult = "TypeCtrlBreak"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeInsert:         strResult = "TypeInsert"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypePrintScreen:    strResult = "TypePrintScreen"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeAltPrintScreen: strResult = "TypeAltPrintScreen"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_Mouse:              strResult = "Mouse"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_MouseIntegration:   strResult = "MouseIntegration"; break;
+        case UIExtraDataMetaDefs::RuntimeMenuInputActionType_All:                strResult = "All"; break;
         default:
         {
             AssertMsgFailed(("No text for action type=%d", runtimeMenuInputActionType));
@@ -693,18 +695,20 @@ template<> UIExtraDataMetaDefs::RuntimeMenuInputActionType fromInternalString<UI
 {
     /* Here we have some fancy stuff allowing us
      * to search through the keys using 'case-insensitive' rule: */
-    QStringList keys;            QList<UIExtraDataMetaDefs::RuntimeMenuInputActionType> values;
-    keys << "Keyboard";          values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_Keyboard;
-    keys << "KeyboardSettings";  values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_KeyboardSettings;
-    keys << "TypeCAD";           values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCAD;
+    QStringList keys;             QList<UIExtraDataMetaDefs::RuntimeMenuInputActionType> values;
+    keys << "Keyboard";           values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_Keyboard;
+    keys << "KeyboardSettings";   values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_KeyboardSettings;
+    keys << "TypeCAD";            values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCAD;
 #ifdef VBOX_WS_X11
-    keys << "TypeCABS";          values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCABS;
+    keys << "TypeCABS";           values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCABS;
 #endif /* VBOX_WS_X11 */
-    keys << "TypeCtrlBreak";     values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCtrlBreak;
-    keys << "TypeInsert";        values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeInsert;
-    keys << "Mouse";             values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_Mouse;
-    keys << "MouseIntegration";  values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_MouseIntegration;
-    keys << "All";               values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_All;
+    keys << "TypeCtrlBreak";      values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeCtrlBreak;
+    keys << "TypeInsert";         values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeInsert;
+    keys << "TypePrintScreen";    values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypePrintScreen;
+    keys << "TypeAltPrintScreen"; values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeAltPrintScreen;
+    keys << "Mouse";              values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_Mouse;
+    keys << "MouseIntegration";   values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_MouseIntegration;
+    keys << "All";                values << UIExtraDataMetaDefs::RuntimeMenuInputActionType_All;
     /* Invalid type for unknown words: */
     if (!keys.contains(strRuntimeMenuInputActionType, Qt::CaseInsensitive))
         return UIExtraDataMetaDefs::RuntimeMenuInputActionType_Invalid;
diff --git a/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataDefs.h b/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataDefs.h
index 3bee354..ccbfaed 100644
--- a/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataDefs.h
+++ b/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataDefs.h
@@ -425,18 +425,20 @@ public:
     /** Runtime UI: Menu "Input": Action types. */
     enum RuntimeMenuInputActionType
     {
-        RuntimeMenuInputActionType_Invalid           = 0,
-        RuntimeMenuInputActionType_Keyboard          = RT_BIT(0),
-        RuntimeMenuInputActionType_KeyboardSettings  = RT_BIT(1),
-        RuntimeMenuInputActionType_TypeCAD           = RT_BIT(2),
+        RuntimeMenuInputActionType_Invalid            = 0,
+        RuntimeMenuInputActionType_Keyboard           = RT_BIT(0),
+        RuntimeMenuInputActionType_KeyboardSettings   = RT_BIT(1),
+        RuntimeMenuInputActionType_TypeCAD            = RT_BIT(2),
 #ifdef VBOX_WS_X11
-        RuntimeMenuInputActionType_TypeCABS          = RT_BIT(3),
+        RuntimeMenuInputActionType_TypeCABS           = RT_BIT(3),
 #endif /* VBOX_WS_X11 */
-        RuntimeMenuInputActionType_TypeCtrlBreak     = RT_BIT(4),
-        RuntimeMenuInputActionType_TypeInsert        = RT_BIT(5),
-        RuntimeMenuInputActionType_Mouse             = RT_BIT(6),
-        RuntimeMenuInputActionType_MouseIntegration  = RT_BIT(7),
-        RuntimeMenuInputActionType_All               = 0xFFFF
+        RuntimeMenuInputActionType_TypeCtrlBreak      = RT_BIT(4),
+        RuntimeMenuInputActionType_TypeInsert         = RT_BIT(5),
+        RuntimeMenuInputActionType_TypePrintScreen    = RT_BIT(6),
+        RuntimeMenuInputActionType_TypeAltPrintScreen = RT_BIT(7),
+        RuntimeMenuInputActionType_Mouse              = RT_BIT(8),
+        RuntimeMenuInputActionType_MouseIntegration   = RT_BIT(9),
+        RuntimeMenuInputActionType_All                = 0xFFFF
     };
 
     /** Runtime UI: Menu "Devices": Action types. */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIActionPool.h b/src/VBox/Frontends/VirtualBox/src/globals/UIActionPool.h
index c83d62b..c51d872 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIActionPool.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIActionPool.h
@@ -188,6 +188,7 @@ public:
 
     /** Retranslates action. */
     virtual void retranslateUi() = 0;
+    virtual ~UIAction() { delete menu(); }
 
 protected:
 
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
index 985c212..1cf602e 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
@@ -136,4 +136,15 @@ struct StorageSlot
 };
 Q_DECLARE_METATYPE(StorageSlot);
 
+/** Common UI: Storage-slot struct extension with exact controller name. */
+struct ExactStorageSlot : public StorageSlot
+{
+    ExactStorageSlot(const QString &strController,
+                     KStorageBus enmBus, LONG iPort, LONG iDevice)
+        : StorageSlot(enmBus, iPort, iDevice)
+        , controller(strController)
+    {}
+    QString controller;
+};
+
 #endif /* !___UIDefs_h___ */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
index eb7a869..f30b71a 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
@@ -22,6 +22,9 @@
 /* Qt includes: */
 # include <QApplication>
 # include <QDesktopWidget>
+# ifdef VBOX_WS_X11
+#  include <QTimer>
+# endif
 # if QT_VERSION >= 0x050000
 #  include <QScreen>
 # endif /* QT_VERSION >= 0x050000 */
@@ -34,6 +37,7 @@
 
 /* Other VBox includes: */
 # include <iprt/assert.h>
+# include <VBox/log.h>
 
 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
 
@@ -59,13 +63,25 @@ public:
     /** Constructs invisible window for the host-screen with @a iHostScreenIndex. */
     UIInvisibleWindow(int iHostScreenIndex);
 
+private slots:
+
+    /** Performs fallback drop. */
+    void sltFallback();
+
 private:
 
+    /** Move @a pEvent handler. */
+    void moveEvent(QMoveEvent *pEvent);
     /** Resize @a pEvent handler. */
     void resizeEvent(QResizeEvent *pEvent);
 
     /** Holds the index of the host-screen this window created for. */
-    int m_iHostScreenIndex;
+    const int m_iHostScreenIndex;
+
+    /** Holds whether the move event came. */
+    bool m_fMoveCame;
+    /** Holds whether the resize event came. */
+    bool m_fResizeCame;
 };
 
 
@@ -76,6 +92,8 @@ private:
 UIInvisibleWindow::UIInvisibleWindow(int iHostScreenIndex)
     : QWidget(0, Qt::Window | Qt::FramelessWindowHint)
     , m_iHostScreenIndex(iHostScreenIndex)
+    , m_fMoveCame(false)
+    , m_fResizeCame(false)
 {
     /* Resize to minimum size of 1 pixel: */
     resize(1, 1);
@@ -84,10 +102,56 @@ UIInvisibleWindow::UIInvisibleWindow(int iHostScreenIndex)
     /* For composite WMs make this 1 pixel transparent: */
     if (vboxGlobal().isCompositingManagerRunning())
         setAttribute(Qt::WA_TranslucentBackground);
+    /* Install fallback handler: */
+    QTimer::singleShot(5000, this, SLOT(sltFallback()));
+}
+
+void UIInvisibleWindow::sltFallback()
+{
+    /* Sanity check for fallback geometry: */
+    QRect fallbackGeometry(x(), y(), width(), height());
+    if (   fallbackGeometry.width() <= 1
+        || fallbackGeometry.height() <= 1)
+        fallbackGeometry = gpDesktop->screenGeometry(m_iHostScreenIndex);
+    LogRel(("GUI: UIInvisibleWindow::sltFallback: %s event haven't came. "
+            "Screen: %d, work area: %dx%d x %dx%d\n",
+            !m_fMoveCame ? "Move" : !m_fResizeCame ? "Resize" : "Some",
+            m_iHostScreenIndex, fallbackGeometry.x(), fallbackGeometry.y(), fallbackGeometry.width(), fallbackGeometry.height()));
+    emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, fallbackGeometry);
+}
+
+void UIInvisibleWindow::moveEvent(QMoveEvent *pEvent)
+{
+    /* We do have both move and resize events,
+     * with no idea who will come first, but we need
+     * to send a final signal after last of events arrived. */
+
+    /* Call to base-class: */
+    QWidget::moveEvent(pEvent);
+
+    /* Ignore 'not-yet-shown' case: */
+    if (!isVisible())
+        return;
+
+    /* Mark move event as received: */
+    m_fMoveCame = true;
+
+    /* If the resize event already came: */
+    if (m_fResizeCame)
+    {
+        /* Notify listeners about host-screen available-geometry was calulated: */
+        LogRel2(("GUI: UIInvisibleWindow::moveEvent: Screen: %d, work area: %dx%d x %dx%d\n", m_iHostScreenIndex,
+                 x(), y(), width(), height()));
+        emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, QRect(x(), y(), width(), height()));
+    }
 }
 
 void UIInvisibleWindow::resizeEvent(QResizeEvent *pEvent)
 {
+    /* We do have both move and resize events,
+     * with no idea who will come first, but we need
+     * to send a final signal after last of events arrived. */
+
     /* Call to base-class: */
     QWidget::resizeEvent(pEvent);
 
@@ -95,8 +159,17 @@ void UIInvisibleWindow::resizeEvent(QResizeEvent *pEvent)
     if (!isVisible())
         return;
 
-    /* Notify listeners about host-screen available-geometry was calulated: */
-    emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, QRect(x(), y(), width(), height()));
+    /* Mark resize event as received: */
+    m_fResizeCame = true;
+
+    /* If the move event already came: */
+    if (m_fMoveCame)
+    {
+        /* Notify listeners about host-screen available-geometry was calulated: */
+        LogRel2(("GUI: UIInvisibleWindow::resizeEvent: Screen: %d, work area: %dx%d x %dx%d\n", m_iHostScreenIndex,
+                 x(), y(), width(), height()));
+        emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, QRect(x(), y(), width(), height()));
+    }
 }
 
 #endif /* VBOX_WS_X11 */
@@ -283,11 +356,10 @@ bool UIDesktopWidgetWatchdog::isFakeScreenDetected() const
 }
 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
 
+#if QT_VERSION < 0x050000
+
 void UIDesktopWidgetWatchdog::sltHandleHostScreenCountChanged(int cHostScreenCount)
 {
-    Q_UNUSED(cHostScreenCount);
-
-#if QT_VERSION < 0x050000
 //    printf("UIDesktopWidgetWatchdog::sltHandleHostScreenCountChanged(%d)\n", cHostScreenCount);
 
 # ifdef VBOX_WS_X11
@@ -297,16 +369,46 @@ void UIDesktopWidgetWatchdog::sltHandleHostScreenCountChanged(int cHostScreenCou
 
     /* Notify listeners: */
     emit sigHostScreenCountChanged(cHostScreenCount);
-#endif /* QT_VERSION < 0x050000 */
 }
 
-void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen)
+void UIDesktopWidgetWatchdog::sltHandleHostScreenResized(int iHostScreenIndex)
 {
-    Q_UNUSED(pHostScreen);
+//    printf("UIDesktopWidgetWatchdog::sltHandleHostScreenResized(%d)\n", iHostScreenIndex);
 
-#if QT_VERSION >= 0x050000
+# ifdef VBOX_WS_X11
+    /* Update host-screen available-geometry: */
+    updateHostScreenAvailableGeometry(iHostScreenIndex);
+# endif /* VBOX_WS_X11 */
+
+    /* Notify listeners: */
+    emit sigHostScreenResized(iHostScreenIndex);
+}
+
+void UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized(int iHostScreenIndex)
+{
+//    printf("UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized(%d)\n", iHostScreenIndex);
+
+# ifdef VBOX_WS_X11
+    /* Update host-screen available-geometry: */
+    updateHostScreenAvailableGeometry(iHostScreenIndex);
+# endif /* VBOX_WS_X11 */
+
+    /* Notify listeners: */
+    emit sigHostScreenWorkAreaResized(iHostScreenIndex);
+}
+
+#else /* QT_VERSION >= 0x050000 */
+
+void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen)
+{
 //    printf("UIDesktopWidgetWatchdog::sltHostScreenAdded(%d)\n", screenCount());
 
+    /* Listen for screen signals: */
+    connect(pHostScreen, SIGNAL(geometryChanged(const QRect &)),
+            this, SLOT(sltHandleHostScreenResized(const QRect &)));
+    connect(pHostScreen, SIGNAL(availableGeometryChanged(const QRect &)),
+            this, SLOT(sltHandleHostScreenWorkAreaResized(const QRect &)));
+
 # ifdef VBOX_WS_X11
     /* Update host-screen configuration: */
     updateHostScreenConfiguration();
@@ -314,16 +416,18 @@ void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen)
 
     /* Notify listeners: */
     emit sigHostScreenCountChanged(screenCount());
-#endif /* QT_VERSION >= 0x050000 */
 }
 
 void UIDesktopWidgetWatchdog::sltHostScreenRemoved(QScreen *pHostScreen)
 {
-    Q_UNUSED(pHostScreen);
-
-#if QT_VERSION >= 0x050000
 //    printf("UIDesktopWidgetWatchdog::sltHostScreenRemoved(%d)\n", screenCount());
 
+    /* Forget about screen signals: */
+    disconnect(pHostScreen, SIGNAL(geometryChanged(const QRect &)),
+               this, SLOT(sltHandleHostScreenResized(const QRect &)));
+    disconnect(pHostScreen, SIGNAL(availableGeometryChanged(const QRect &)),
+               this, SLOT(sltHandleHostScreenWorkAreaResized(const QRect &)));
+
 # ifdef VBOX_WS_X11
     /* Update host-screen configuration: */
     updateHostScreenConfiguration();
@@ -331,35 +435,63 @@ void UIDesktopWidgetWatchdog::sltHostScreenRemoved(QScreen *pHostScreen)
 
     /* Notify listeners: */
     emit sigHostScreenCountChanged(screenCount());
-#endif /* QT_VERSION >= 0x050000 */
 }
 
-void UIDesktopWidgetWatchdog::sltHandleHostScreenResized(int iHostScreenIndex)
+void UIDesktopWidgetWatchdog::sltHandleHostScreenResized(const QRect &geometry)
 {
-//    printf("UIDesktopWidgetWatchdog::sltHandleHostScreenResized(%d)\n", iHostScreenIndex);
+    /* Get the screen: */
+    QScreen *pScreen = sender() ? qobject_cast<QScreen*>(sender()) : 0;
+    AssertPtrReturnVoid(pScreen);
 
-#ifdef VBOX_WS_X11
+    /* Determine screen index: */
+    const int iHostScreenIndex = qApp->screens().indexOf(pScreen);
+    AssertReturnVoid(iHostScreenIndex != -1);
+    LogRel(("GUI: UIDesktopWidgetWatchdog::sltHandleHostScreenResized: "
+            "Screen %d is formally resized to: %dx%d x %dx%d\n",
+            iHostScreenIndex, geometry.x(), geometry.y(),
+            geometry.width(), geometry.height()));
+
+# ifdef VBOX_WS_X11
     /* Update host-screen available-geometry: */
     updateHostScreenAvailableGeometry(iHostScreenIndex);
-#endif /* VBOX_WS_X11 */
+# endif /* VBOX_WS_X11 */
 
     /* Notify listeners: */
     emit sigHostScreenResized(iHostScreenIndex);
 }
 
-void UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized(int iHostScreenIndex)
+void UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized(const QRect &availableGeometry)
 {
-//    printf("UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized(%d)\n", iHostScreenIndex);
+    /* Get the screen: */
+    QScreen *pScreen = sender() ? qobject_cast<QScreen*>(sender()) : 0;
+    AssertPtrReturnVoid(pScreen);
+
+    /* Determine screen index: */
+    const int iHostScreenIndex = qApp->screens().indexOf(pScreen);
+    AssertReturnVoid(iHostScreenIndex != -1);
+    LogRel(("GUI: UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized: "
+            "Screen %d work area is formally resized to: %dx%d x %dx%d\n",
+            iHostScreenIndex, availableGeometry.x(), availableGeometry.y(),
+            availableGeometry.width(), availableGeometry.height()));
+
+# ifdef VBOX_WS_X11
+    /* Update host-screen available-geometry: */
+    updateHostScreenAvailableGeometry(iHostScreenIndex);
+# endif /* VBOX_WS_X11 */
 
     /* Notify listeners: */
     emit sigHostScreenWorkAreaResized(iHostScreenIndex);
 }
 
+#endif /* QT_VERSION >= 0x050000 */
+
 #ifdef VBOX_WS_X11
 void UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated(int iHostScreenIndex, QRect availableGeometry)
 {
-//    printf("UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated(%d): %dx%d x %dx%d\n",
-//           iHostScreenIndex, availableGeometry.x(), availableGeometry.y(), availableGeometry.width(), availableGeometry.height());
+    LogRel(("GUI: UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated: "
+            "Screen %d work area is actually resized to: %dx%d x %dx%d\n",
+            iHostScreenIndex, availableGeometry.x(), availableGeometry.y(),
+            availableGeometry.width(), availableGeometry.height()));
 
     /* Apply received data: */
     const bool fSendSignal = m_availableGeometryData.value(iHostScreenIndex).isValid();
@@ -379,11 +511,21 @@ void UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated(int
 void UIDesktopWidgetWatchdog::prepare()
 {
     /* Prepare connections: */
+#if QT_VERSION < 0x050000
     connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(sltHandleHostScreenCountChanged(int)));
-    connect(qApp, SIGNAL(screenAdded(QScreen *)), this, SLOT(sltHostScreenAdded(QScreen *)));
-    connect(qApp, SIGNAL(screenRemoved(QScreen *)), this, SLOT(sltHostScreenRemoved(QScreen *)));
     connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(sltHandleHostScreenResized(int)));
     connect(QApplication::desktop(), SIGNAL(workAreaResized(int)), this, SLOT(sltHandleHostScreenWorkAreaResized(int)));
+#else /* QT_VERSION >= 0x050000 */
+    connect(qApp, SIGNAL(screenAdded(QScreen *)), this, SLOT(sltHostScreenAdded(QScreen *)));
+    connect(qApp, SIGNAL(screenRemoved(QScreen *)), this, SLOT(sltHostScreenRemoved(QScreen *)));
+    foreach (QScreen *pHostScreen, qApp->screens())
+    {
+        connect(pHostScreen, SIGNAL(geometryChanged(const QRect &)),
+                this, SLOT(sltHandleHostScreenResized(const QRect &)));
+        connect(pHostScreen, SIGNAL(availableGeometryChanged(const QRect &)),
+                this, SLOT(sltHandleHostScreenWorkAreaResized(const QRect &)));
+    }
+#endif /* QT_VERSION >= 0x050000 */
 
 #ifdef VBOX_WS_X11
     /* Update host-screen configuration: */
@@ -394,11 +536,21 @@ void UIDesktopWidgetWatchdog::prepare()
 void UIDesktopWidgetWatchdog::cleanup()
 {
     /* Cleanup connections: */
+#if QT_VERSION < 0x050000
     disconnect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(sltHandleHostScreenCountChanged(int)));
-    disconnect(qApp, SIGNAL(screenAdded(QScreen *)), this, SLOT(sltHostScreenAdded(QScreen *)));
-    disconnect(qApp, SIGNAL(screenRemoved(QScreen *)), this, SLOT(sltHostScreenRemoved(QScreen *)));
     disconnect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(sltHandleHostScreenResized(int)));
     disconnect(QApplication::desktop(), SIGNAL(workAreaResized(int)), this, SLOT(sltHandleHostScreenWorkAreaResized(int)));
+#else /* QT_VERSION >= 0x050000 */
+    disconnect(qApp, SIGNAL(screenAdded(QScreen *)), this, SLOT(sltHostScreenAdded(QScreen *)));
+    disconnect(qApp, SIGNAL(screenRemoved(QScreen *)), this, SLOT(sltHostScreenRemoved(QScreen *)));
+    foreach (QScreen *pHostScreen, qApp->screens())
+    {
+        disconnect(pHostScreen, SIGNAL(geometryChanged(const QRect &)),
+                   this, SLOT(sltHandleHostScreenResized(const QRect &)));
+        disconnect(pHostScreen, SIGNAL(availableGeometryChanged(const QRect &)),
+                   this, SLOT(sltHandleHostScreenWorkAreaResized(const QRect &)));
+    }
+#endif /* QT_VERSION >= 0x050000 */
 
 #ifdef VBOX_WS_X11
     /* Cleanup existing workers finally: */
@@ -449,7 +601,7 @@ void UIDesktopWidgetWatchdog::updateHostScreenAvailableGeometry(int iHostScreenI
                 this, SLOT(sltHandleHostScreenAvailableGeometryCalculated(int, QRect)));
 
         /* Place worker to corresponding host-screen: */
-        pWorker->move(hostScreenGeometry.topLeft());
+        pWorker->move(hostScreenGeometry.center());
         /* And finally, maximize it: */
         pWorker->showMaximized();
     }
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
index 9013b79..4247d75 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
@@ -107,18 +107,23 @@ public:
 
 private slots:
 
+#if QT_VERSION < 0x050000
     /** Handles host-screen count change to @a cHostScreenCount. */
     void sltHandleHostScreenCountChanged(int cHostScreenCount);
-    /** Handles @a pHostScreen adding. */
-    void sltHostScreenAdded(QScreen *pHostScreen);
-    /** Handles @a pHostScreen removing. */
-    void sltHostScreenRemoved(QScreen *pHostScreen);
-
     /** Handles resize for the host-screen with @a iHostScreenIndex. */
     void sltHandleHostScreenResized(int iHostScreenIndex);
-
     /** Handles work-area resize for the host-screen with @a iHostScreenIndex. */
     void sltHandleHostScreenWorkAreaResized(int iHostScreenIndex);
+#else /* QT_VERSION >= 0x050000 */
+    /** Handles @a pHostScreen adding. */
+    void sltHostScreenAdded(QScreen *pHostScreen);
+    /** Handles @a pHostScreen removing. */
+    void sltHostScreenRemoved(QScreen *pHostScreen);
+    /** Handles host-screen resize to passed @a geometry. */
+    void sltHandleHostScreenResized(const QRect &geometry);
+    /** Handles host-screen work-area resize to passed @a availableGeometry. */
+    void sltHandleHostScreenWorkAreaResized(const QRect &availableGeometry);
+#endif /* QT_VERSION >= 0x050000 */
 
 #ifdef VBOX_WS_X11
     /** Handles @a availableGeometry calculation result for the host-screen with @a iHostScreenIndex. */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.h b/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.h
index a140905..aa11db7 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.h
@@ -80,10 +80,10 @@ public:
 protected:
 
     /** Icon-pool constructor. */
-    UIIconPool() {};
+    UIIconPool() {}
 
     /** Icon-pool destructor. */
-    virtual ~UIIconPool() {};
+    virtual ~UIIconPool() {}
 
 private:
 
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
index 5dc64ca..9a2629f 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
@@ -440,10 +440,15 @@ void UIMessageCenter::cannotCreateVirtualBoxClient(const CVirtualBoxClient &clie
 
 void UIMessageCenter::cannotAcquireVirtualBox(const CVirtualBoxClient &client) const
 {
-    error(0, MessageType_Critical,
-          tr("<p>Failed to acquire the VirtualBox COM object.</p>"
-             "<p>The application will now terminate.</p>"),
-          formatErrorInfo(client));
+    QString err = tr("<p>Failed to acquire the VirtualBox COM object.</p>"
+                     "<p>The application will now terminate.</p>");
+#if defined(VBOX_WS_X11) || defined(VBOX_WS_MAC)
+    if (client.lastRC() == NS_ERROR_SOCKET_FAIL)
+        err += tr("<p>The reason for this error are most likely wrong permissions of the IPC "
+                  "daemon socket due to an installation problem. Please check the permissions of "
+                  "<font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p>");
+#endif
+    error(0, MessageType_Critical, err, formatErrorInfo(client));
 }
 
 void UIMessageCenter::cannotFindLanguage(const QString &strLangId, const QString &strNlsPath) const
diff --git a/src/VBox/Frontends/VirtualBox/src/main.cpp b/src/VBox/Frontends/VirtualBox/src/main.cpp
index acbe36f..1b96202 100644
--- a/src/VBox/Frontends/VirtualBox/src/main.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/main.cpp
@@ -275,7 +275,7 @@ static void QtMessageOutput(QtMsgType type, const QMessageLogContext &context, c
 /** Qt4 message handler, function that prints out
   * debug, warning, critical, fatal and system error messages.
   * @param  type  Holds the type of the message.
-  * @param  pMsg  Holds the the message body. */
+  * @param  pMsg  Holds the message body. */
 static void QtMessageOutput(QtMsgType type, const char *pMsg)
 {
 # ifndef VBOX_WS_X11
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIAbstractDockIconPreview.h b/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIAbstractDockIconPreview.h
index dfdf17e..008ab96 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIAbstractDockIconPreview.h
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIAbstractDockIconPreview.h
@@ -33,7 +33,7 @@ class UIAbstractDockIconPreview
 {
 public:
     UIAbstractDockIconPreview(UISession *pSession, const QPixmap& overlayImage);
-    virtual ~UIAbstractDockIconPreview() {};
+    virtual ~UIAbstractDockIconPreview() {}
 
     virtual void updateDockOverlay() = 0;
     virtual void updateDockPreview(CGImageRef VMImage) = 0;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.cpp
index 096a81d..5c8b821 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.cpp
@@ -1190,6 +1190,66 @@ protected:
     }
 };
 
+class UIActionSimplePerformTypePrintScreen : public UIActionSimple
+{
+    Q_OBJECT;
+
+public:
+
+    UIActionSimplePerformTypePrintScreen(UIActionPool *pParent)
+        : UIActionSimple(pParent, ":/hostkey_16px.png", ":/hostkey_disabled_16px.png") {}
+
+protected:
+
+    /** Returns action extra-data ID. */
+    virtual int extraDataID() const { return UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypePrintScreen; }
+    /** Returns action extra-data key. */
+    virtual QString extraDataKey() const { return gpConverter->toInternalString(UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypePrintScreen); }
+    /** Returns whether action is allowed. */
+    virtual bool isAllowed() const { return actionPool()->toRuntime()->isAllowedInMenuInput(UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypePrintScreen); }
+
+    QString shortcutExtraDataID() const
+    {
+        return QString("TypePrintScreen");
+    }
+
+    void retranslateUi()
+    {
+        setName(QApplication::translate("UIActionPool", "&Insert %1", "that means send the %1 key sequence to the virtual machine").arg("Print Screen"));
+        setStatusTip(QApplication::translate("UIActionPool", "Send the %1 sequence to the virtual machine").arg("Print Screen"));
+    }
+};
+
+class UIActionSimplePerformTypeAltPrintScreen : public UIActionSimple
+{
+    Q_OBJECT;
+
+public:
+
+    UIActionSimplePerformTypeAltPrintScreen(UIActionPool *pParent)
+        : UIActionSimple(pParent, ":/hostkey_16px.png", ":/hostkey_disabled_16px.png") {}
+
+protected:
+
+    /** Returns action extra-data ID. */
+    virtual int extraDataID() const { return UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeAltPrintScreen; }
+    /** Returns action extra-data key. */
+    virtual QString extraDataKey() const { return gpConverter->toInternalString(UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeAltPrintScreen); }
+    /** Returns whether action is allowed. */
+    virtual bool isAllowed() const { return actionPool()->toRuntime()->isAllowedInMenuInput(UIExtraDataMetaDefs::RuntimeMenuInputActionType_TypeAltPrintScreen); }
+
+    QString shortcutExtraDataID() const
+    {
+        return QString("TypeAltPrintScreen");
+    }
+
+    void retranslateUi()
+    {
+        setName(QApplication::translate("UIActionPool", "&Insert %1", "that means send the %1 key sequence to the virtual machine").arg("Alt Print Screen"));
+        setStatusTip(QApplication::translate("UIActionPool", "Send the %1 sequence to the virtual machine").arg("Alt Print Screen"));
+    }
+};
+
 class UIActionMenuMouse : public UIActionMenu
 {
     Q_OBJECT;
@@ -2144,6 +2204,8 @@ void UIActionPoolRuntime::preparePool()
 #endif /* VBOX_WS_X11 */
     m_pool[UIActionIndexRT_M_Input_M_Keyboard_S_TypeCtrlBreak] = new UIActionSimplePerformTypeCtrlBreak(this);
     m_pool[UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert] = new UIActionSimplePerformTypeInsert(this);
+    m_pool[UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen] = new UIActionSimplePerformTypePrintScreen(this);
+    m_pool[UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen] = new UIActionSimplePerformTypeAltPrintScreen(this);
     m_pool[UIActionIndexRT_M_Input_M_Mouse] = new UIActionMenuMouse(this);
     m_pool[UIActionIndexRT_M_Input_M_Mouse_T_Integration] = new UIActionToggleMouseIntegration(this);
 
@@ -2867,6 +2929,10 @@ void UIActionPoolRuntime::updateMenuInputKeyboard()
     fSeparator = addAction(pMenu, action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCtrlBreak)) || fSeparator;
     /* 'Type Insert' action: */
     fSeparator = addAction(pMenu, action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert)) || fSeparator;
+    /* 'Type Print Screen' action: */
+    fSeparator = addAction(pMenu, action(UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen)) || fSeparator;
+    /* 'Type Alt Print Screen' action: */
+    fSeparator = addAction(pMenu, action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen)) || fSeparator;
 
     /* Mark menu as valid: */
     m_invalidations.remove(UIActionIndexRT_M_Input_M_Keyboard);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.h
index db33eeb..90df7fc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIActionPoolRuntime.h
@@ -87,6 +87,8 @@ enum UIActionIndexRT
 #endif /* VBOX_WS_X11 */
     UIActionIndexRT_M_Input_M_Keyboard_S_TypeCtrlBreak,
     UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert,
+    UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen,
+    UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen,
     UIActionIndexRT_M_Input_M_Mouse,
     UIActionIndexRT_M_Input_M_Mouse_T_Integration,
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp
index 63620a5..01f059f 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp
@@ -84,7 +84,7 @@ bool UIDnDMIMEData::hasFormat(const QString &strMIMEType) const
  * data in case of a successful drag'n drop operation.
  *
  * @param strMIMEType           MIME type string.
- * @param vaType                Variant containing the actual data based on the the MIME type.
+ * @param vaType                Variant containing the actual data based on the MIME type.
  *
  * @return QVariant
  */
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
index 6b191b8..c01e421 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
@@ -1380,9 +1380,17 @@ void UIFrameBufferPrivate::paintDefault(QPaintEvent *pEvent)
 
 #ifdef VBOX_WS_MAC
 # if QT_VERSION >= 0x050000
+    /* On OSX for Qt5 we need to erase backing store first: */
+    QRect eraseRect = paintRect;
+    /* Take the backing-scale-factor into account: */
+    if (useUnscaledHiDPIOutput() && backingScaleFactor() > 1.0)
+    {
+        eraseRect.moveTo(eraseRect.topLeft() / backingScaleFactor());
+        eraseRect.setSize(eraseRect.size() / backingScaleFactor());
+    }
     /* Replace translucent background with black one: */
     painter.setCompositionMode(QPainter::CompositionMode_Source);
-    painter.fillRect(paintRect, QColor(Qt::black));
+    painter.fillRect(eraseRect, QColor(Qt::black));
     painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
 # endif /* QT_VERSION >= 0x050000 */
 #endif /* VBOX_WS_MAC */
@@ -1458,9 +1466,17 @@ void UIFrameBufferPrivate::paintSeamless(QPaintEvent *pEvent)
 
 #if defined(VBOX_WITH_TRANSLUCENT_SEAMLESS)
 # if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11) || QT_VERSION >= 0x050000
+    /* On OSX for Qt5 we need to erase backing store first: */
+    QRect eraseRect = paintRect;
+    /* Take the backing-scale-factor into account: */
+    if (useUnscaledHiDPIOutput() && backingScaleFactor() > 1.0)
+    {
+        eraseRect.moveTo(eraseRect.topLeft() / backingScaleFactor());
+        eraseRect.setSize(eraseRect.size() / backingScaleFactor());
+    }
     /* Replace translucent background with black one: */
     painter.setCompositionMode(QPainter::CompositionMode_Source);
-    painter.fillRect(paintRect, QColor(Qt::black));
+    painter.fillRect(eraseRect, QColor(Qt::black));
     painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
 # endif /* VBOX_WS_WIN || VBOX_WS_X11 || QT_VERSION >= 0x050000 */
 #endif /* VBOX_WITH_TRANSLUCENT_SEAMLESS */
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
index a0128bb..dd2fcb7 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
@@ -1018,6 +1018,8 @@ void UIMachineLogic::prepareActionGroups()
 #endif /* VBOX_WS_X11 */
     m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCtrlBreak));
     m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert));
+    m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen));
+    m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen));
 
     /* Move actions into running-n-paused actions group: */
     m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_Detach));
@@ -1130,6 +1132,10 @@ void UIMachineLogic::prepareActionConnections()
             this, SLOT(sltTypeCtrlBreak()));
     connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert), SIGNAL(triggered()),
             this, SLOT(sltTypeInsert()));
+    connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen), SIGNAL(triggered()),
+            this, SLOT(sltTypePrintScreen()));
+    connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen), SIGNAL(triggered()),
+            this, SLOT(sltTypeAltPrintScreen()));
     connect(actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration), SIGNAL(toggled(bool)),
             this, SLOT(sltToggleMouseIntegration(bool)));
 
@@ -1504,6 +1510,38 @@ void UIMachineLogic::sltTypeInsert()
     AssertWrapperOk(keyboard());
 }
 
+void UIMachineLogic::sltTypePrintScreen()
+{
+    static QVector<LONG> sequence(8);
+    sequence[0] = 0xE0;        /* Extended flag */
+    sequence[1] = 0x2A;        /* Print.. down */
+    sequence[2] = 0xE0;        /* Extended flag */
+    sequence[3] = 0x37;        /* ..Screen down */
+    sequence[4] = 0xE0;        /* Extended flag */
+    sequence[5] = 0x37 | 0x80; /* ..Screen up */
+    sequence[6] = 0xE0;        /* Extended flag */
+    sequence[7] = 0x2A | 0x80; /* Print.. up */
+    keyboard().PutScancodes(sequence);
+    AssertWrapperOk(keyboard());
+}
+
+void UIMachineLogic::sltTypeAltPrintScreen()
+{
+    static QVector<LONG> sequence(10);
+    sequence[0] = 0x38;        /* Alt down */
+    sequence[1] = 0xE0;        /* Extended flag */
+    sequence[2] = 0x2A;        /* Print.. down */
+    sequence[3] = 0xE0;        /* Extended flag */
+    sequence[4] = 0x37;        /* ..Screen down */
+    sequence[5] = 0xE0;        /* Extended flag */
+    sequence[6] = 0x37 | 0x80; /* ..Screen up */
+    sequence[7] = 0xE0;        /* Extended flag */
+    sequence[8] = 0x2A | 0x80; /* Print.. up */
+    sequence[9] = 0x38 | 0x80; /* Alt up */
+    keyboard().PutScancodes(sequence);
+    AssertWrapperOk(keyboard());
+}
+
 void UIMachineLogic::sltTakeSnapshot()
 {
     /* Do not process if window(s) missed! */
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
index 2f6472f..ccdec8c 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
@@ -264,6 +264,8 @@ private slots:
 #endif /* VBOX_WS_X11 */
     void sltTypeCtrlBreak();
     void sltTypeInsert();
+    void sltTypePrintScreen();
+    void sltTypeAltPrintScreen();
     void sltTakeSnapshot();
     void sltShowInformationDialog();
     void sltReset();
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMenuBarEditorWindow.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMenuBarEditorWindow.cpp
index 79ac476..49ee348 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMenuBarEditorWindow.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMenuBarEditorWindow.cpp
@@ -59,6 +59,20 @@ UIMenuBarEditorWidget::UIMenuBarEditorWidget(QWidget *pParent,
 #ifndef VBOX_WS_MAC
     , m_pCheckBoxEnable(0)
 #endif /* !VBOX_WS_MAC */
+    , m_restrictionsOfMenuBar(UIExtraDataMetaDefs::MenuType_Invalid)
+    , m_restrictionsOfMenuApplication(UIExtraDataMetaDefs::MenuApplicationActionType_Invalid)
+    , m_restrictionsOfMenuMachine(UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Invalid)
+    , m_restrictionsOfMenuView(UIExtraDataMetaDefs::RuntimeMenuViewActionType_Invalid)
+    , m_restrictionsOfMenuInput(UIExtraDataMetaDefs::RuntimeMenuInputActionType_Invalid)
+    , m_restrictionsOfMenuDevices(UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Invalid)
+#ifdef VBOX_WITH_DEBUGGER_GUI
+    , m_restrictionsOfMenuDebug(UIExtraDataMetaDefs::RuntimeMenuDebuggerActionType_Invalid)
+#endif
+#ifdef VBOX_WS_MAC
+    , m_restrictionsOfMenuWindow(UIExtraDataMetaDefs::MenuWindowActionType_Invalid)
+#endif
+    , m_restrictionsOfMenuHelp(UIExtraDataMetaDefs::MenuHelpActionType_Invalid)
+
 {
     /* Prepare: */
     prepare();
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
index f94e9be..9ca0d4d 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
@@ -591,27 +591,30 @@ void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
     /* Make sure GA medium ID is valid: */
     AssertReturnVoid(!strMediumID.isNull());
 
-    /* Searching for the first suitable controller/slot: */
-    QString strControllerName;
-    LONG iCntPort = -1, iCntDevice = -1;
+    /* Search for a suitable storage slots: */
+    QList<ExactStorageSlot> freeStorageSlots;
+    QList<ExactStorageSlot> busyStorageSlots;
     foreach (const CStorageController &controller, machine().GetStorageControllers())
     {
         foreach (const CMediumAttachment &attachment, machine().GetMediumAttachmentsOfController(controller.GetName()))
         {
+            /* Look for an optical device: */
             if (attachment.GetType() == KDeviceType_DVD)
             {
-                strControllerName = controller.GetName();
-                iCntPort = attachment.GetPort();
-                iCntDevice = attachment.GetDevice();
-                break;
+                /* Append storage slot to corresponding list: */
+                if (attachment.GetMedium().isNull())
+                    freeStorageSlots << ExactStorageSlot(controller.GetName(), controller.GetBus(),
+                                                         attachment.GetPort(), attachment.GetDevice());
+                else
+                    busyStorageSlots << ExactStorageSlot(controller.GetName(), controller.GetBus(),
+                                                         attachment.GetPort(), attachment.GetDevice());
             }
         }
-        if (!strControllerName.isNull())
-            break;
     }
 
-    /* Make sure suitable controller/slot were found: */
-    if (strControllerName.isNull())
+    /* Make sure at least one storage slot found: */
+    QList<ExactStorageSlot> storageSlots = freeStorageSlots + busyStorageSlots;
+    if (storageSlots.isEmpty())
     {
         msgCenter().cannotMountGuestAdditions(machineName());
         return;
@@ -626,20 +629,19 @@ void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
         vboxGlobal().createMedium(medium);
     }
 
-    /* Mount medium to corresponding controller/slot: */
-    machine().MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), false /* force */);
+    /* Try to mount medium to first storage slot: */
+    bool fMounted = false;
+    while (!storageSlots.isEmpty() && !fMounted)
+    {
+        const ExactStorageSlot storageSlot = storageSlots.takeFirst();
+        machine().MountMedium(storageSlot.controller, storageSlot.port, storageSlot.device, medium.medium(), false /* force */);
+        if (machine().isOk())
+            fMounted = true;
+    }
     if (!machine().isOk())
     {
-        /* Ask for force mounting: */
-        if (msgCenter().cannotRemountMedium(machine(), medium, true /* mount? */,
-                                            true /* retry? */, mainMachineWindow()))
-        {
-            /* Force mount medium to the predefined port/device: */
-            machine().MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), true /* force */);
-            if (!machine().isOk())
-                msgCenter().cannotRemountMedium(machine(), medium, true /* mount? */,
-                                                false /* retry? */, mainMachineWindow());
-        }
+        msgCenter().cannotRemountMedium(machine(), medium, true /* mount? */,
+                                        false /* retry? */, mainMachineWindow());
     }
 }
 
@@ -1130,12 +1132,13 @@ void UISession::prepareConnections()
             this, SLOT(sltHandleHostScreenCountChange()));
     connect(gpDesktop, SIGNAL(sigHostScreenResized(int)),
             this, SLOT(sltHandleHostScreenGeometryChange()));
-    connect(gpDesktop, SIGNAL(sigHostScreenWorkAreaResized(int)),
-            this, SLOT(sltHandleHostScreenAvailableAreaChange()));
 # ifdef VBOX_WS_X11
     connect(gpDesktop, SIGNAL(sigHostScreenWorkAreaRecalculated(int)),
             this, SLOT(sltHandleHostScreenAvailableAreaChange()));
-# endif /* VBOX_WS_X11 */
+# else /* !VBOX_WS_X11 */
+    connect(gpDesktop, SIGNAL(sigHostScreenWorkAreaResized(int)),
+            this, SLOT(sltHandleHostScreenAvailableAreaChange()));
+# endif /* !VBOX_WS_X11 */
 #endif /* !VBOX_WS_MAC */
 }
 
@@ -1252,7 +1255,8 @@ void UISession::prepareScreens()
             display().GetScreenResolution(iScreenIndex,
                                           uGuestWidth, uGuestHeight, uBpp,
                                           iGuestOriginX, iGuestOriginY, enmStatus);
-            m_monitorVisibilityVector[iScreenIndex] = (enmStatus == KGuestMonitorStatus_Enabled);
+            m_monitorVisibilityVector[iScreenIndex] = (   enmStatus == KGuestMonitorStatus_Enabled
+                                                       || enmStatus == KGuestMonitorStatus_Blank);
         }
         /* And make sure at least one of them is visible (primary if others are hidden): */
         if (countOfVisibleWindows() < 1)
@@ -1931,7 +1935,11 @@ void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
     const double dBackingScaleFactor = frameBuffer(uScreenID)->backingScaleFactor();
     /* Adjust backing-scale-factor if necessary: */
     if (dBackingScaleFactor > 1.0 && frameBuffer(uScreenID)->useUnscaledHiDPIOutput())
+    {
+        uXHot /= dBackingScaleFactor;
+        uYHot /= dBackingScaleFactor;
         cursorPixmap.setDevicePixelRatio(dBackingScaleFactor);
+    }
 #  endif /* VBOX_GUI_WITH_HIDPI */
 # endif /* VBOX_WS_MAC */
     /* Set the new cursor: */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
index dd4e365..fdd0fd2 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
@@ -42,6 +42,7 @@ struct UIDataSettingsMachineUSBFilter
         , m_strPort(QString())
         , m_strRemote(QString())
         , m_action(KUSBDeviceFilterAction_Null)
+        , m_fHostUSBDevice(false)
         , m_hostUSBDeviceState(KUSBDeviceState_NotSupported) {}
     /* Functions: */
     bool equal(const UIDataSettingsMachineUSBFilter &other) const
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSBFilterDetails.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSBFilterDetails.cpp
index bcc59d2..c50b75d 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSBFilterDetails.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSBFilterDetails.cpp
@@ -39,7 +39,7 @@ UIMachineSettingsUSBFilterDetails::UIMachineSettingsUSBFilterDetails(QWidget *pP
     mLeName->setValidator (new QRegExpValidator (QRegExp (".+"), this));
     mLeVendorID->setValidator (new QRegExpValidator (QRegExp ("[0-9a-fA-F]{0,4}"), this));
     mLeProductID->setValidator (new QRegExpValidator (QRegExp ("[0-9a-fA-F]{0,4}"), this));
-    mLeRevision->setValidator (new QRegExpValidator (QRegExp ("[0-9]{0,4}"), this));
+    mLeRevision->setValidator (new QRegExpValidator (QRegExp ("[0-9a-fA-F]{0,4}"), this));
     mLePort->setValidator (new QRegExpValidator (QRegExp ("[0-9]*"), this));
 
     /* Applying language settings */
diff --git a/src/VBox/Frontends/VirtualBox/src/wizards/newvd/UIWizardNewVDPageBasic3.cpp b/src/VBox/Frontends/VirtualBox/src/wizards/newvd/UIWizardNewVDPageBasic3.cpp
index c08a34e..56a3c7f 100644
--- a/src/VBox/Frontends/VirtualBox/src/wizards/newvd/UIWizardNewVDPageBasic3.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/wizards/newvd/UIWizardNewVDPageBasic3.cpp
@@ -201,8 +201,8 @@ int UIWizardNewVDPage3::calculateSliderScale(qulonglong uMaximumMediumSize)
         // Slider tick count (maximum - minimum) is limited with some
         // "magical number" - 588351, having it more than that brings
         // unpredictable results like slider token jumping and disappearing,
-        // so we are limiting tick count by lowering slider-scale 100 times.
-        iSliderScale /= 100;
+        // so we are limiting tick count by lowering slider-scale 128 times.
+        iSliderScale /= 128;
 #endif /* VBOX_WS_MAC */
     }
     return qMax(iSliderScale, 8);
diff --git a/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp b/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp
index 807521f..77cbe68 100644
--- a/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/wizards/newvm/UIWizardNewVMPageBasic1.cpp
@@ -83,11 +83,11 @@ static const osTypePattern gs_OSTypePattern[] =
     { QRegExp(  "Wi.*32",                         Qt::CaseInsensitive), "Windows7" },
 
     /* Solaris: */
-    { QRegExp("So.*11",                                                 Qt::CaseInsensitive), "Solaris11_64" },
-    { QRegExp("((Op.*So)|(os20[01][0-9])|(So.*10)|(India)|(Neva)).*64", Qt::CaseInsensitive), "OpenSolaris_64" },
-    { QRegExp("((Op.*So)|(os20[01][0-9])|(So.*10)|(India)|(Neva)).*32", Qt::CaseInsensitive), "OpenSolaris" },
-    { QRegExp("So.*64",                                                 Qt::CaseInsensitive), "Solaris_64" },
-    { QRegExp("So.*32",                                                 Qt::CaseInsensitive), "Solaris" },
+    { QRegExp("Sol.*11",                                                  Qt::CaseInsensitive), "Solaris11_64" },
+    { QRegExp("((Op.*Sol)|(os20[01][0-9])|(Sol.*10)|(India)|(Neva)).*64", Qt::CaseInsensitive), "OpenSolaris_64" },
+    { QRegExp("((Op.*Sol)|(os20[01][0-9])|(Sol.*10)|(India)|(Neva)).*32", Qt::CaseInsensitive), "OpenSolaris" },
+    { QRegExp("Sol.*64",                                                  Qt::CaseInsensitive), "Solaris_64" },
+    { QRegExp("Sol.*32",                                                  Qt::CaseInsensitive), "Solaris" },
 
     /* OS/2: */
     { QRegExp( "OS[/|!-]{,1}2.*W.*4.?5",    Qt::CaseInsensitive), "OS2Warp45" },
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
index f527e25..ceb7583 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
@@ -1094,6 +1094,38 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, RTLDRSIGNATURETYP
 
 
 /**
+ * RTTimeNow equivaltent that handles ring-3 where we cannot use it.
+ *
+ * @returns pNow
+ * @param   pNow                Where to return the current time.
+ */
+static PRTTIMESPEC supHardNtTimeNow(PRTTIMESPEC pNow)
+{
+#ifdef IN_RING3
+    /*
+     * Just read system time.
+     */
+    KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
+# ifdef RT_ARCH_AMD64
+    uint64_t uRet = *(uint64_t volatile *)&pUserSharedData->SystemTime; /* This is what KeQuerySystemTime does (missaligned). */
+    return RTTimeSpecSetNtTime(pNow, uRet);
+# else
+
+    LARGE_INTEGER NtTime;
+    do
+    {
+        NtTime.HighPart = pUserSharedData->SystemTime.High1Time;
+        NtTime.LowPart  = pUserSharedData->SystemTime.LowPart;
+    } while (pUserSharedData->SystemTime.High2Time != NtTime.HighPart);
+    return RTTimeSpecSetNtTime(pNow, NtTime.QuadPart);
+# endif
+#else  /* IN_RING0 */
+    return RTTimeNow(pNow);
+#endif /* IN_RING0 */
+}
+
+
+/**
  * Verifies the given loader image.
  *
  * @returns IPRT status code.
@@ -1172,6 +1204,10 @@ DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pw
      *         use this as a minimum timestamp for further build cert
      *         validations.  This works around issues with old DLLs that
      *         we sign against with our certificate (crt, sdl, qt).
+     *
+     * Update: If the validation fails, retry with the current timestamp. This
+     *         is a workaround for NTDLL.DLL in build 14971 having a weird
+     *         timestamp: 0xDF1E957E (Sat Aug 14 14:05:18 2088).
      */
     int rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
     if (RT_SUCCESS(rc))
@@ -1190,6 +1226,16 @@ DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pw
             g_uBuildTimestampHack = pNtViRdr->uTimestamp;
 #endif
 
+        if (rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME)
+        {
+            RTTIMESPEC Now;
+            uint64_t uOld = pNtViRdr->uTimestamp;
+            pNtViRdr->uTimestamp = RTTimeSpecGetSeconds(supHardNtTimeNow(&Now));
+            SUP_DPRINTF(("%ls: VERR_CR_X509_CPV_NOT_VALID_AT_TIME for %#RX64; retrying against current time: %#RX64.\n",
+                         pwszName, uOld, pNtViRdr->uTimestamp)); NOREF(uOld);
+            rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
+        }
+
         /*
          * Microsoft doesn't sign a whole bunch of DLLs, so we have to
          * ASSUME that a bunch of system DLLs are fine.
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
index 9dc9e74..38279cf 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
@@ -141,7 +141,7 @@ typedef struct VERIFIERCACHEENTRY
     /** The verification result. */
     int                     rc;
     /** Used for shutting up load and error messages after a while so they don't
-     * flood the the log file and fill up the disk. */
+     * flood the log file and fill up the disk. */
     uint32_t volatile       cHits;
     /** The validation flags (for WinVerifyTrust retry). */
     uint32_t                fFlags;
diff --git a/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp b/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
index 47c7b23..a0527f8 100644
--- a/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
@@ -36,7 +36,7 @@
 /**
  * The Dll main entry point.
  * @remarks The dllexport is for forcing the linker to generate an import
- *          library, so the the build system doesn't get confused.
+ *          library, so the build system doesn't get confused.
  */
 extern "C" __declspec(dllexport)
 BOOL __stdcall DllMainEntrypoint(HANDLE hModule, DWORD dwReason, PVOID pvReserved)
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
index 6a1de35..e0109a2 100644
--- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
@@ -223,8 +223,10 @@ static void crServerTearDown( void )
     crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
     cr_server.barriers = NULL;
 
+#if 0 /** @todo @bugref{8662} -- can trigger SEGFAULTs during savestate */
     /* Free all context info */
     crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
+#endif
 
     /* synchronize with reality */
     if (!fContextsDeleted)
diff --git a/src/VBox/Installer/darwin/Makefile.kmk b/src/VBox/Installer/darwin/Makefile.kmk
index e64d13b..5dfa81f 100644
--- a/src/VBox/Installer/darwin/Makefile.kmk
+++ b/src/VBox/Installer/darwin/Makefile.kmk
@@ -711,12 +711,6 @@ if 1
 				) \
 			$(VBOX_PATH_VBOX_APP_TMP)/Contents/$(f)$(NLTAB) )
 endif
-ifdef VBOX_WITH_QTGUI_V5
-	$(QUIET)$(APPEND) $(VBOX_PATH_VBOX_APP_TMP)/Contents/Resources/qt.conf "[Paths]"
-	$(QUIET)$(APPEND) $(VBOX_PATH_VBOX_APP_TMP)/Contents/Resources/qt.conf "Prefix =" /Applications/VirtualBox.app/Contents
-	$(QUIET)$(APPEND) $(VBOX_PATH_VBOX_APP_TMP)/Contents/Resources/VirtualBoxVM.app/Contents/Resources/qt.conf "[Paths]"
-	$(QUIET)$(APPEND) $(VBOX_PATH_VBOX_APP_TMP)/Contents/Resources/VirtualBoxVM.app/Contents/Resources/qt.conf "Prefix =" /Applications/VirtualBox.app/Contents
-endif # VBOX_WITH_QTGUI_V5
 ifdef VBOX_WITH_DTRACE
 	@# DTrace library, testcases and scripts.
 	$(MKDIR) -p -m 0755 -- \
diff --git a/src/VBox/Installer/linux/distributions_rpm b/src/VBox/Installer/linux/distributions_rpm
index 03e5d98..b928581 100644
--- a/src/VBox/Installer/linux/distributions_rpm
+++ b/src/VBox/Installer/linux/distributions_rpm
@@ -6,6 +6,7 @@ openSUSE113     = OPENSUSE_11_3
 sles11.0        = SLES_11_0
 sles10.1        = SLES_10_1
 mdv2011.0       = MANDRIVA_2011_0
+fedora25        = FEDORA_25
 fedora24        = FEDORA_24
 fedora22        = FEDORA_22
 fedora21        = FEDORA_21
diff --git a/src/VBox/Installer/linux/rpm/rules b/src/VBox/Installer/linux/rpm/rules
index d144026..14b620d 100755
--- a/src/VBox/Installer/linux/rpm/rules
+++ b/src/VBox/Installer/linux/rpm/rules
@@ -105,7 +105,7 @@ ifneq ($(MAKECMDGOALS),clean)
   $(error Cannot detect package distribution (rpmrel=$(rpmrel)))
  endif
 
- ifeq ($(filter-out el5 el6 el7 fedora18 fedora19 fedora20 fedora21 fedora22 fedora24,$(rpmrel)),)
+ ifeq ($(filter-out el5 el6 el7 fedora18 fedora19 fedora20 fedora21 fedora22 fedora24 fedora25,$(rpmrel)),)
   rpmspec := rpm_redhat
  endif
  ifeq ($(filter-out openSUSE110 openSUSE111 openSUSE112 openSUSE113 openSUSE114 openSUSE123 openSUSE131 openSUSE132,$(rpmrel)),)
diff --git a/src/VBox/Installer/solaris/Makefile.kmk b/src/VBox/Installer/solaris/Makefile.kmk
index 1c239e7..894904e 100644
--- a/src/VBox/Installer/solaris/Makefile.kmk
+++ b/src/VBox/Installer/solaris/Makefile.kmk
@@ -212,7 +212,7 @@ SOLARIS_INSTALLER_FILES = \
 # List of kernel module files that are copied from INST_BIN to platform/i86pc/kernel/drv/[amd64/] and stripped of debug info.
 SOLARIS_FILE_LIST_VARS += SOLARIS_DRIVER_BINS
 SOLARIS_DRIVER_BINS.SUBDIRS := no
-SOLARIS_DRIVER_BINS.STRIP   := yes
+SOLARIS_DRIVER_BINS.STRIP   := no
 SOLARIS_DRIVER_BINS.MODE    := 0644
 SOLARIS_DRIVER_BINS.SRC     := $(PATH_STAGE_BIN)
 SOLARIS_DRIVER_BINS.DST     := $(VBOX_PATH_SI_SCRATCH_PKG)/platform/i86pc/kernel/drv/$(subst x86,,$(KBUILD_TARGET_ARCH))
diff --git a/src/VBox/Installer/win/Makefile.kmk b/src/VBox/Installer/win/Makefile.kmk
index 8ab7cf9..bc67b2f 100644
--- a/src/VBox/Installer/win/Makefile.kmk
+++ b/src/VBox/Installer/win/Makefile.kmk
@@ -616,6 +616,7 @@ $(VBOX_WIN_INST_OUT_DIR)/VBoxMerge$(module)_$(lang).wixobj: \
 		-E 'VBOX_GUI_USE_QGL=$(if $(VBOX_GUI_USE_QGL),yes,no)' \
 		-E 'VBOX_MIDL_PROXY_CLSID=$(VBOX_MIDL_PROXY_CLSID)' \
 		-E 'VBOX_WINDOWS_ICON_FILE=$(subst /,\,$(VBOX_WINDOWS_ICON_FILE))' \
+		-E 'VBOX_QT_INFIX=$(VBOX_QT_INFIX)' \
 		-E 'VBOX_WITH_32_ON_64_MAIN_API=$(if $(VBOX_WITH_32_ON_64_MAIN_API),yes,no)' \
 		-E 'VBOX_WITH_ADDITIONS_PACKING=$(if $(VBOX_WITH_ADDITIONS_PACKING),yes,no)' \
 		-E 'VBOX_WITH_COMBINED_PACKAGE=$(if $(VBOX_WITH_COMBINED_PACKAGE),yes,no)' \
diff --git a/src/VBox/Installer/win/VBoxMergeApp.wxi b/src/VBox/Installer/win/VBoxMergeApp.wxi
index 605d61f..d86fece 100644
--- a/src/VBox/Installer/win/VBoxMergeApp.wxi
+++ b/src/VBox/Installer/win/VBoxMergeApp.wxi
@@ -112,16 +112,6 @@
     <?include $(env.PATH_TARGET)\DirComponentsAndFiles_DTrace.wxi ?>
 
 
-    <!--
-
-    <Component Id="cp_StartMenuShortcut" Guid="1C137D24-E599-47BD-98D0-2F62F202A8EA" Win64="$(var.Property_Win64)">
-        <RegistryValue Root="HKCU" Key="$(var.Property_RegKeyInstall)" Type="string"
-                       Value="installed" KeyPath="yes" />
-        <Shortcut Id="ShortcutStartMenuVBox" Directory="ProgramMenuDir"
-                  Name="VirtualBox" WorkingDirectory="INSTALLDIR" Advertise="no" Target="VirtualBox.exe" />
-        <RemoveFolder Id="ShortcutStartMenuVBoxRemove" On="uninstall" />
-    </Component>-->
-
     <!---->
 
 <?if $(env.VBOX_WITH_QTGUI) = "yes" ?>
@@ -192,10 +182,7 @@
         <File Id="file_VBoxManage.exe" Name="VBoxManage.exe"
               Source="$(env.PATH_OUT)\bin\VBoxManage.exe" />
         <File Id="file_VBoxHeadless.exe" Name="VBoxHeadless.exe"
-              Source="$(env.PATH_OUT)\bin\VBoxHeadless.exe">
-            <!-- Create a simple shortcut for VBoxVRDP, which is not present anymore, pointing to VBoxHeadless.exe -->
-       <!--     <Shortcut Id="ShortcutVBoxVRDP" Directory="INSTALLDIR" Name="VBoxVRDP" Show="normal" WorkingDirectory="INSTALLDIR"/> -->
-        </File>
+              Source="$(env.PATH_OUT)\bin\VBoxHeadless.exe" />
 <?if $(env.VBOX_WITH_HARDENING) = "yes" ?>
         <File Id="file_VBoxHeadless.dll" Name="VBoxHeadless.dll"
               Source="$(env.PATH_OUT)\bin\VBoxHeadless.dll">
@@ -228,7 +215,7 @@
               Source="$(env.PATH_OUT)\bin\VBoxExtPackHelperApp.exe"/>
 <?endif ?>
 <?if $(env.VBOX_WITH_DTRACE) = "yes" ?>
-	 <File Id="file_VBoxDTrace.exe" Name="VBoxDTrace.exe" Source="$(env.PATH_OUT)\bin\VBoxDTrace.exe" />
+        <File Id="file_VBoxDTrace.exe" Name="VBoxDTrace.exe" Source="$(env.PATH_OUT)\bin\VBoxDTrace.exe" />
 <?endif ?>
         <!-- VBox DLL files -->
         <File Id="file_VBoxDD.dll" Name="VBoxDD.dll"
diff --git a/src/VBox/Installer/win/VBoxMergeCOM32On64.wxs b/src/VBox/Installer/win/VBoxMergeCOM32On64.wxs
index 03cd88b..8bd3d5a 100644
--- a/src/VBox/Installer/win/VBoxMergeCOM32On64.wxs
+++ b/src/VBox/Installer/win/VBoxMergeCOM32On64.wxs
@@ -37,11 +37,11 @@
 
         <!-- Here comes the file/directory list -->
         <Directory Id="TARGETDIR" Name="SourceDir">
-            <Directory Id="MergeRedirectFolder" FileSource=".">
+            <Directory Id="msm_VBoxApplicationFolder" FileSource=".">
 
                 <?include VBoxMergeCOM32On64.wxi ?>
 
-            </Directory> <!-- MergeRedirectFolder -->
+            </Directory> <!-- msm_VBoxApplicationFolder -->
         </Directory> <!-- TARGETDIR -->
 
     </Module>
diff --git a/src/VBox/Installer/win/VirtualBox_TypeLib.xsl b/src/VBox/Installer/win/VirtualBox_TypeLib.xsl
index 319eff3..5d2ddc5 100644
--- a/src/VBox/Installer/win/VirtualBox_TypeLib.xsl
+++ b/src/VBox/Installer/win/VirtualBox_TypeLib.xsl
@@ -66,7 +66,7 @@
       <xsl:attribute name="MinorVersion"><xsl:value-of select="substring(@version,3)"/></xsl:attribute>
       <xsl:attribute name="Language">0</xsl:attribute>
       <xsl:attribute name="Description"><xsl:value-of select="@desc"/></xsl:attribute>
-      <xsl:attribute name="HelpDirectory"><xsl:text>INSTALLDIR</xsl:text></xsl:attribute>
+      <xsl:attribute name="HelpDirectory"><xsl:text>msm_VBoxApplicationFolder</xsl:text></xsl:attribute>
       <AppId>
         <xsl:attribute name="Id"><xsl:value-of select="@appUuid"/></xsl:attribute>
         <xsl:attribute name="Description"><xsl:value-of select="@name"/> Application</xsl:attribute>
diff --git a/src/VBox/Installer/win/VirtualBox_TypeLibWithInterfaces.xsl b/src/VBox/Installer/win/VirtualBox_TypeLibWithInterfaces.xsl
index b7925d0..42fd64e 100644
--- a/src/VBox/Installer/win/VirtualBox_TypeLibWithInterfaces.xsl
+++ b/src/VBox/Installer/win/VirtualBox_TypeLibWithInterfaces.xsl
@@ -75,7 +75,7 @@
       <xsl:attribute name="MinorVersion"><xsl:value-of select="substring(@version,3)"/></xsl:attribute>
       <xsl:attribute name="Language">0</xsl:attribute>
       <xsl:attribute name="Description"><xsl:value-of select="@desc"/></xsl:attribute>
-      <xsl:attribute name="HelpDirectory"><xsl:text>INSTALLDIR</xsl:text></xsl:attribute>
+      <xsl:attribute name="HelpDirectory"><xsl:text>msm_VBoxApplicationFolder</xsl:text></xsl:attribute>
       <AppId>
         <xsl:attribute name="Id"><xsl:value-of select="@appUuid"/></xsl:attribute>
         <xsl:attribute name="Description"><xsl:value-of select="@name"/> Application</xsl:attribute>
diff --git a/src/VBox/Main/Makefile.kmk b/src/VBox/Main/Makefile.kmk
index de792dd..451844a 100644
--- a/src/VBox/Main/Makefile.kmk
+++ b/src/VBox/Main/Makefile.kmk
@@ -785,9 +785,12 @@ VBoxC_SOURCES = \
 	$(VBOX_XML_SCHEMADEFS_CPP)
 
 # Audio bits.
+VBoxC_DEFS    += \
+	$(if $(VBOX_WITH_AUDIO_50), VBOX_WITH_AUDIO_50,)
+
 VBoxC_SOURCES += \
-	../Devices/Audio/AudioMixBuffer.cpp \
-	../Devices/Audio/DrvAudioCommon.cpp \
+	../Devices/$(VBOX_AUDIO_PATH_SOURCES)/AudioMixBuffer.cpp \
+	../Devices/$(VBOX_AUDIO_PATH_SOURCES)/DrvAudioCommon.cpp \
 	$(if $(VBOX_WITH_VRDE_AUDIO),src-client/DrvAudioVRDE$(VBOX_AUDIO_FILE_SUFFIX).cpp,)
 
 VBoxC_SOURCES.win = \
diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.c b/src/VBox/Main/cbinding/VBoxCAPIGlue.c
index 333ea20..293c029 100644
--- a/src/VBox/Main/cbinding/VBoxCAPIGlue.c
+++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.c
@@ -32,19 +32,24 @@
 /*********************************************************************************************************************************
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
+/* NOTE: do NOT use any include files here which are only available in the
+ * VirtualBox tree, e.g. iprt. They are not available in the SDK, which is
+ * where this file will provided as source code and has to be compilable. */
 #include "VBoxCAPIGlue.h"
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#ifdef WIN32
+# define _INTPTR 2 /* on Windows stdint.h compares this in #if, causing warnings if not defined */
+#endif /* WIN32 */
+#include <stdint.h>
 #ifndef WIN32
-# include <stdint.h>
 # include <dlfcn.h>
 # include <pthread.h>
 #else /* WIN32 */
-# include <iprt/stdint.h>
-# include <iprt/win/windows.h>
+# include <Windows.h>
 #endif /* WIN32 */
 
 
diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl
index 7cb62e2..fa029cd 100644
--- a/src/VBox/Main/idl/VirtualBox.xidl
+++ b/src/VBox/Main/idl/VirtualBox.xidl
@@ -14872,7 +14872,7 @@ Snapshot 1 (B.vdi)            Snapshot 1 (B.vdi)
         the properties of this medium or contents of the storage unit
         will return an error (unless explicitly stated otherwise). That
         includes an attempt to start a virtual machine that wants to
-        write to the the medium.
+        write to the medium.
 
         When the virtual machine is started up, it locks for reading all
         media it uses in read-only mode. If some medium cannot be locked
diff --git a/src/VBox/Main/include/DrvAudioVRDE_50.h b/src/VBox/Main/include/DrvAudioVRDE_50.h
new file mode 100644
index 0000000..6c5e420
--- /dev/null
+++ b/src/VBox/Main/include/DrvAudioVRDE_50.h
@@ -0,0 +1,64 @@
+/* $Id: DrvAudioVRDE_50.h $ */
+/** @file
+ * VirtualBox driver interface to VRDE backend.
+ */
+
+/*
+ * Copyright (C) 2014-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ____H_DRVAUDIOVRDE
+#define ____H_DRVAUDIOVRDE
+
+#include <VBox/com/ptr.h>
+#include <VBox/RemoteDesktop/VRDE.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmifs.h>
+
+class Console;
+
+class AudioVRDE
+{
+
+public:
+
+    AudioVRDE(Console *pConsole);
+    virtual ~AudioVRDE(void);
+
+public:
+
+    static const PDMDRVREG DrvReg;
+
+    Console *getParent(void) { return mParent; }
+
+public:
+
+    int onVRDEControl(bool fEnable, uint32_t uFlags);
+    int onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin);
+    int onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData);
+    int onVRDEInputEnd(void *pvContext);
+    int onVRDEInputIntercept(bool fIntercept);
+
+public:
+
+    static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
+    static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
+
+private:
+
+    /** Pointer to the associated VRDE audio driver. */
+    struct DRVAUDIOVRDE *mpDrv;
+    /** Pointer to parent. */
+    Console * const mParent;
+};
+
+#endif /* !____H_DRVAUDIOVRDE */
+
diff --git a/src/VBox/Main/include/DrvAudioVideoRec_50.h b/src/VBox/Main/include/DrvAudioVideoRec_50.h
new file mode 100644
index 0000000..4a4a1a4
--- /dev/null
+++ b/src/VBox/Main/include/DrvAudioVideoRec_50.h
@@ -0,0 +1,62 @@
+/* $Id: DrvAudioVideoRec_50.h $ */
+/** @file
+ * VirtualBox driver interface to video recording backend.
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ____H_DRVAUDIOVIDEOREC
+#define ____H_DRVAUDIOVIDEOREC
+
+#include <VBox/com/ptr.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmifs.h>
+
+class Console;
+
+class AudioVideoRec
+{
+
+public:
+
+    AudioVideoRec(Console *pConsole);
+    virtual ~AudioVideoRec(void);
+
+public:
+
+    static const PDMDRVREG DrvReg;
+
+    Console *getParent(void) { return mParent; }
+
+public:
+
+    int handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept);
+    int handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels, int cBits, bool fUnsigned);
+    int handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData);
+    int handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext);
+
+public:
+
+    static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
+    static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
+
+private:
+
+    /** Pointer to the associated video recording audio driver. */
+    struct DRVAUDIOVIDEOREC *mpDrv;
+    /** Pointer to parent. */
+    Console * const mParent;
+};
+
+#endif /* !____H_DRVAUDIOVIDEOREC */
+
diff --git a/src/VBox/Main/src-all/Global.cpp b/src/VBox/Main/src-all/Global.cpp
index 0448163..fd31386 100644
--- a/src/VBox/Main/src-all/Global.cpp
+++ b/src/VBox/Main/src-all/Global.cpp
@@ -342,7 +342,7 @@ const Global::OSType Global::sOSTypes[] =
         StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97, AudioCodecType_STAC9700  },
 
     { "Solaris", "Solaris",           "Solaris11_64",       "Oracle Solaris 11 (64-bit)",
-      VBOXOSTYPE_Solaris11_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET,
+      VBOXOSTYPE_Solaris11_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_USBTABLET | VBOXOSHINT_RTCUTC,
       1536,  16, 16 * _1G64, NetworkAdapterType_I82540EM, 0, StorageControllerType_IntelAhci, StorageBus_SATA,
         StorageControllerType_IntelAhci, StorageBus_SATA, ChipsetType_PIIX3, AudioControllerType_AC97, AudioCodecType_STAC9700  },
 
diff --git a/src/VBox/Main/src-client/DisplayImpl.cpp b/src/VBox/Main/src-client/DisplayImpl.cpp
index 956693f..d71394a 100644
--- a/src/VBox/Main/src-client/DisplayImpl.cpp
+++ b/src/VBox/Main/src-client/DisplayImpl.cpp
@@ -1600,8 +1600,11 @@ HRESULT Display::getScreenResolution(ULONG aScreenId, ULONG *aWidth, ULONG *aHei
     DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
 
     GuestMonitorStatus_T guestMonitorStatus = GuestMonitorStatus_Enabled;
+
     if (pFBInfo->flags & VBVA_SCREEN_F_DISABLED)
         guestMonitorStatus = GuestMonitorStatus_Disabled;
+    else if (pFBInfo->flags & (VBVA_SCREEN_F_BLANK | VBVA_SCREEN_F_BLANK2))
+        guestMonitorStatus = GuestMonitorStatus_Blank;
 
     if (aWidth)
         *aWidth = pFBInfo->w;
diff --git a/src/VBox/Main/src-client/DrvAudioVRDE_50.cpp b/src/VBox/Main/src-client/DrvAudioVRDE_50.cpp
new file mode 100644
index 0000000..201f8dd
--- /dev/null
+++ b/src/VBox/Main/src-client/DrvAudioVRDE_50.cpp
@@ -0,0 +1,618 @@
+/* $Id: DrvAudioVRDE_50.cpp $ */
+/** @file
+ * VRDE audio backend for Main.
+ */
+
+/*
+ * Copyright (C) 2013-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_VRDE_AUDIO
+#include <VBox/log.h>
+#include "DrvAudioVRDE_50.h"
+#include "ConsoleImpl.h"
+#include "ConsoleVRDPServer.h"
+
+#include "Logging.h"
+
+#include "../../Devices/Audio_50/DrvAudio.h"
+#include "../../Devices/Audio_50/AudioMixBuffer.h"
+
+#include <iprt/mem.h>
+#include <iprt/cdefs.h>
+#include <iprt/circbuf.h>
+
+#include <VBox/vmm/pdmaudioifs.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/RemoteDesktop/VRDE.h>
+#include <VBox/vmm/cfgm.h>
+#include <VBox/err.h>
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * Audio VRDE driver instance data.
+ */
+typedef struct DRVAUDIOVRDE
+{
+    /** Pointer to audio VRDE object. */
+    AudioVRDE           *pAudioVRDE;
+    PPDMDRVINS           pDrvIns;
+    /** Pointer to the driver instance structure. */
+    PDMIHOSTAUDIO        IHostAudio;
+    /** Pointer to the VRDP's console object. */
+    ConsoleVRDPServer   *pConsoleVRDPServer;
+    /** Pointer to the DrvAudio port interface that is above us. */
+    PPDMIAUDIOCONNECTOR  pDrvAudio;
+    /** Whether this driver is enabled or not. */
+    bool                 fEnabled;
+} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
+
+typedef struct VRDESTREAMIN
+{
+    /** Associated host input stream. */
+    PDMAUDIOHSTSTRMIN    HstStrmIn;
+    /** Number of samples captured asynchronously in the
+     *  onVRDEInputXXX callbacks. */
+    uint32_t             cSamplesCaptured;
+    /** Critical section. */
+    RTCRITSECT           CritSect;
+} VRDESTREAMIN, *PVRDESTREAMIN;
+
+typedef struct VRDESTREAMOUT
+{
+    /** Associated host output stream. */
+    PDMAUDIOHSTSTRMOUT HstStrmOut;
+    uint64_t old_ticks;
+    uint64_t cSamplesSentPerSec;
+} VRDESTREAMOUT, *PVRDESTREAMOUT;
+
+
+
+static DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
+{
+    RT_NOREF(pInterface);
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVRDEInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                            PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+                                            PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
+{
+    RT_NOREF(pCfgAcq, enmRecSource);
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
+    AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
+
+    if (pcSamples)
+        *pcSamples = _4K; /** @todo Make this configurable. */
+
+    return DrvAudioStreamCfgToProps(pCfgReq, &pVRDEStrmIn->HstStrmIn.Props);
+}
+
+static DECLCALLBACK(int) drvAudioVRDEInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                             PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, uint32_t *pcSamples)
+{
+    RT_NOREF(pCfgAcq);
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
+    AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
+
+    if (pcSamples)
+        *pcSamples = _4K; /** @todo Make this configurable. */
+
+    return DrvAudioStreamCfgToProps(pCfgReq, &pVRDEStrmOut->HstStrmOut.Props);
+}
+
+static DECLCALLBACK(bool) drvAudioVRDEIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, false);
+
+    NOREF(enmDir);
+
+    if (!pDrv->fEnabled)
+        return false;
+
+    return true;
+}
+
+/**
+ * {FIXME - Missing brief description - FIXME}
+ *
+ * Transfers audio input formerly sent by a connected RDP client / VRDE backend
+ * (using the onVRDEInputXXX methods) over to the VRDE host (VM). The audio device
+ * emulation then will read and send the data to the guest.
+ *
+ * @return  IPRT status code.
+ * @param   pInterface
+ * @param   pHstStrmIn
+ * @param   pcSamplesCaptured
+ */
+static DECLCALLBACK(int) drvAudioVRDECaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                               uint32_t *pcSamplesCaptured)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+    AssertPtrReturn(pcSamplesCaptured, VERR_INVALID_POINTER);
+
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
+    AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
+
+    /** @todo Use CritSect! */
+
+    int rc;
+
+    uint32_t cProcessed = 0;
+    if (pVRDEStrmIn->cSamplesCaptured)
+    {
+        rc = AudioMixBufMixToParent(&pVRDEStrmIn->HstStrmIn.MixBuf, pVRDEStrmIn->cSamplesCaptured,
+                                    &cProcessed);
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    if (RT_SUCCESS(rc))
+    {
+        *pcSamplesCaptured = cProcessed;
+
+        Assert(pVRDEStrmIn->cSamplesCaptured >= cProcessed);
+        pVRDEStrmIn->cSamplesCaptured -= cProcessed;
+    }
+
+    LogFlowFunc(("cSamplesCaptured=%RU32, cProcessed=%RU32 rc=%Rrc\n", pVRDEStrmIn->cSamplesCaptured, cProcessed, rc));
+    return rc;
+}
+
+/**
+ * Transfers VM audio output to remote client.
+ *
+ * Transfers VM audio output over to the VRDE instance for playing remotely
+ * on the client.
+ *
+ * @return  IPRT status code.
+ * @param   pInterface
+ * @param   pHstStrmOut
+ * @param   pcSamplesPlayed
+ */
+static DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                             uint32_t *pcSamplesPlayed)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+    /* pcSamplesPlayed is optional. */
+
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
+    AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
+
+    uint32_t live = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+    uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
+    uint64_t ticks = now  - pVRDEStrmOut->old_ticks;
+    uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
+
+    /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
+    uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
+
+    /* Don't play more than available. */
+    if (cSamplesPlayed > live)
+        cSamplesPlayed = live;
+
+    /* Remember when samples were consumed. */
+    pVRDEStrmOut->old_ticks = now;
+
+    VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHstStrmOut->Props.uHz,
+                                                 pHstStrmOut->Props.cChannels,
+                                                 pHstStrmOut->Props.cBits,
+                                                 pHstStrmOut->Props.fSigned);
+
+    int cSamplesToSend = cSamplesPlayed;
+
+    LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
+                 pHstStrmOut->Props.uHz, pHstStrmOut->Props.cChannels,
+                 pHstStrmOut->Props.cBits, pHstStrmOut->Props.fSigned,
+                 format, cSamplesToSend));
+
+    /*
+     * Call the VRDP server with the data.
+     */
+    uint32_t cReadTotal = 0;
+
+    PPDMAUDIOSAMPLE pSamples;
+    uint32_t cRead;
+    int rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend,
+                                &pSamples, &cRead);
+    if (   RT_SUCCESS(rc)
+        && cRead)
+    {
+        cReadTotal = cRead;
+        pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
+
+        if (rc == VINF_TRY_AGAIN)
+        {
+            rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend - cRead,
+                                    &pSamples, &cRead);
+            if (RT_SUCCESS(rc))
+                pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
+
+            cReadTotal += cRead;
+        }
+    }
+
+    AudioMixBufFinish(&pHstStrmOut->MixBuf, cSamplesToSend);
+
+    /*
+     * Always report back all samples acquired, regardless of whether the
+     * VRDP server actually did process those.
+     */
+    if (pcSamplesPlayed)
+        *pcSamplesPlayed = cReadTotal;
+
+    LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+    RT_NOREF(pHstStrmIn);
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    if (pDrv->pConsoleVRDPServer)
+        pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+    RT_NOREF(pHstStrmOut);
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+                                                PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    RT_NOREF(enmStreamCmd);
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
+    AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    AudioMixBufReset(&pHstStrmOut->MixBuf);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+                                               PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+    PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
+    AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
+
+    PPDMAUDIOHSTSTRMIN pThisStrmIn = &pVRDEStrmIn->HstStrmIn;
+
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    if (!pDrv->pConsoleVRDPServer)
+        return VINF_SUCCESS;
+
+    AudioMixBufReset(&pThisStrmIn->MixBuf);
+
+    /* Initialize only if not already done. */
+    int rc;
+    if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
+    {
+        rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, AudioMixBufSize(&pThisStrmIn->MixBuf),
+                                                           pThisStrmIn->Props.uHz,
+                                                           pThisStrmIn->Props.cChannels, pThisStrmIn->Props.cBits);
+        if (rc == VERR_NOT_SUPPORTED)
+        {
+            LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
+            rc = VINF_SUCCESS;
+        }
+    }
+    else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
+    {
+        pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_INVALID_PARAMETER;
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioVRDEGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    RT_NOREF(pInterface);
+    pCfg->cbStreamOut     = sizeof(VRDESTREAMOUT);
+    pCfg->cbStreamIn      = sizeof(VRDESTREAMIN);
+    pCfg->cMaxHstStrmsOut = 1;
+    pCfg->cMaxHstStrmsIn  = 2; /* Microphone in + Line in. */
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+    AssertPtrReturnVoid(pDrv);
+
+    if (pDrv->pConsoleVRDPServer)
+        pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+    return NULL;
+}
+
+AudioVRDE::AudioVRDE(Console *pConsole)
+    : mpDrv(NULL),
+      mParent(pConsole)
+{
+}
+
+AudioVRDE::~AudioVRDE(void)
+{
+    if (mpDrv)
+    {
+        mpDrv->pAudioVRDE = NULL;
+        mpDrv = NULL;
+    }
+}
+
+int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
+{
+    RT_NOREF(uFlags);
+    LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
+
+    if (mpDrv == NULL)
+        return VERR_INVALID_STATE;
+
+    mpDrv->fEnabled = fEnable;
+
+    return VINF_SUCCESS; /* Never veto. */
+}
+
+/**
+ * Marks the beginning of sending captured audio data from a connected
+ * RDP client.
+ *
+ * @return  IPRT status code.
+ * @param   pvContext               The context; in this case a pointer to a
+ *                                  VRDESTREAMIN structure.
+ * @param   pVRDEAudioBegin         Pointer to a VRDEAUDIOINBEGIN structure.
+ */
+int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
+{
+    AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
+    AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
+
+    PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
+    AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
+
+#ifdef LOG_ENABLED
+    VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
+    int iSampleHz  = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt);
+    int cChannels  = VRDE_AUDIO_FMT_CHANNELS(audioFmt);
+    int cBits      = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt);
+    bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt);
+    LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
+                 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
+#endif
+    return VINF_SUCCESS;
+}
+
+int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
+{
+    PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
+    AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
+
+    PPDMAUDIOHSTSTRMIN pHstStrmIn = &pVRDEStrmIn->HstStrmIn;
+    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+    /** @todo Use CritSect! */
+
+    uint32_t cWritten;
+    int rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, pvData, cbData, &cWritten);
+    if (RT_SUCCESS(rc))
+        pVRDEStrmIn->cSamplesCaptured += cWritten;
+
+    LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
+                 cbData, cWritten, pVRDEStrmIn->cSamplesCaptured, rc));
+    return rc;
+}
+
+int AudioVRDE::onVRDEInputEnd(void *pvContext)
+{
+    NOREF(pvContext);
+
+    return VINF_SUCCESS;
+}
+
+int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
+{
+    RT_NOREF(fEnabled);
+    return VINF_SUCCESS; /* Never veto. */
+}
+
+/**
+ * Construct a VRDE audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+/* static */
+DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    RT_NOREF(fFlags);
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+    PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
+    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+    LogRel(("Audio: Initializing VRDE driver\n"));
+    LogFlowFunc(("fFlags=0x%x\n", fFlags));
+
+    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
+                    ("Configuration error: Not possible to attach anything to this driver!\n"),
+                    VERR_PDM_DRVINS_NO_ATTACH);
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
+
+    /* Init defaults. */
+    pThis->fEnabled = false;
+
+    /*
+     * Get the ConsoleVRDPServer object pointer.
+     */
+    void *pvUser;
+    int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
+    AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
+
+    /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
+    pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
+
+    /*
+     * Get the AudioVRDE object pointer.
+     */
+    pvUser = NULL;
+    rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
+    AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
+
+    pThis->pAudioVRDE = (AudioVRDE *)pvUser;
+    pThis->pAudioVRDE->mpDrv = pThis;
+
+    /*
+     * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
+     * Described in CFGM tree.
+     */
+    pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
+    AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnDestruct}
+ */
+/* static */
+DECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
+{
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+    PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
+    LogFlowFuncEnter();
+
+    /*
+     * If the AudioVRDE object is still alive, we must clear it's reference to
+     * us since we'll be invalid when we return from this method.
+     */
+    if (pThis->pAudioVRDE)
+    {
+        pThis->pAudioVRDE->mpDrv = NULL;
+        pThis->pAudioVRDE = NULL;
+    }
+}
+
+
+/**
+ * VRDE audio driver registration record.
+ */
+const PDMDRVREG AudioVRDE::DrvReg =
+{
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "AudioVRDE",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Audio driver for VRDE backend",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVAUDIOVRDE),
+    /* pfnConstruct */
+    AudioVRDE::drvConstruct,
+    /* pfnDestruct */
+    AudioVRDE::drvDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
diff --git a/src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp b/src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp
new file mode 100644
index 0000000..fac64af
--- /dev/null
+++ b/src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp
@@ -0,0 +1,911 @@
+/* $Id: DrvAudioVideoRec_50.cpp $ */
+/** @file
+ * Video recording audio backend for Main.
+ */
+
+/*
+ * Copyright (C) 2014-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include "DrvAudioVideoRec_50.h"
+#include "ConsoleImpl.h"
+#include "ConsoleVRDPServer.h"
+
+#include "Logging.h"
+
+#include <iprt/mem.h>
+#include <iprt/cdefs.h>
+#include <iprt/circbuf.h>
+
+#include <VBox/vmm/pdmaudioifs.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/RemoteDesktop/VRDE.h>
+#include <VBox/vmm/cfgm.h>
+#include <VBox/err.h>
+
+#ifdef LOG_GROUP
+ #undef LOG_GROUP
+#endif
+#define LOG_GROUP LOG_GROUP_DEV_AUDIO
+#include <VBox/log.h>
+
+/* Initialization status indicator used for the recreation of the AudioUnits. */
+#define CA_STATUS_UNINIT    UINT32_C(0) /* The device is uninitialized */
+#define CA_STATUS_IN_INIT   UINT32_C(1) /* The device is currently initializing */
+#define CA_STATUS_INIT      UINT32_C(2) /* The device is initialized */
+#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
+
+//@todo move t_sample as a PDM interface
+//typedef struct { int mute;  uint32_t r; uint32_t l; } volume_t;
+
+#define INT_MAX         0x7fffffff
+volume_t videorec_nominal_volume = {
+    0,
+    INT_MAX,
+    INT_MAX
+};
+
+/* The desired buffer length in milliseconds. Will be the target total stream
+ * latency on newer version of pulse. Apparent latency can be less (or more.)
+ * In case its need to be used. Currently its not used.
+ */
+#if 0
+static struct
+{
+    int         buffer_msecs_out;
+    int         buffer_msecs_in;
+} confAudioVideoRec
+=
+{
+    INIT_FIELD (.buffer_msecs_out = ) 100,
+    INIT_FIELD (.buffer_msecs_in  = ) 100,
+};
+#endif
+
+/**
+ * Audio video recording driver instance data.
+ *
+ * @extends PDMIAUDIOSNIFFERCONNECTOR
+ */
+typedef struct DRVAUDIOVIDEOREC
+{
+    /** Pointer to audio video recording object. */
+    AudioVideoRec      *pAudioVideoRec;
+    PPDMDRVINS          pDrvIns;
+    /** Pointer to the driver instance structure. */
+    PDMIHOSTAUDIO       IHostAudio;
+    ConsoleVRDPServer *pConsoleVRDPServer;
+    /** Pointer to the DrvAudio port interface that is above it. */
+    PPDMIAUDIOCONNECTOR       pUpPort;
+} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
+typedef struct PDMAUDIOHSTSTRMOUT PDMAUDIOHSTSTRMOUT;
+typedef PDMAUDIOHSTSTRMOUT *PPDMAUDIOHSTSTRMOUT;
+
+typedef struct VIDEORECAUDIOIN
+{
+    /* Audio and audio details for recording */
+    PDMAUDIOHSTSTRMIN   pHostVoiceIn;
+    void * pvUserCtx;
+    /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
+    uint32_t cBytesPerFrame;
+    /* Frequency of the actual audio format. */
+    uint32_t uFrequency;
+    /* If the actual format frequence differs from the requested format, this is not NULL. */
+    void *rate;
+    /* Temporary buffer for st_sample_t representation of the input audio data. */
+    void *pvSamplesBuffer;
+    /* buffer for bytes of samples (not rate converted) */
+    uint32_t cbSamplesBufferAllocated;
+    /* Temporary buffer for frequency conversion. */
+    void *pvRateBuffer;
+    /* buffer for bytes rate converted samples */
+    uint32_t cbRateBufferAllocated;
+    /* A ring buffer for transferring data to the playback thread */
+    PRTCIRCBUF pRecordedVoiceBuf;
+    t_sample * convAudioDevFmtToStSampl;
+    uint32_t fIsInit;
+    uint32_t status;
+} VIDEORECAUDIOIN, *PVIDEORECAUDIOIN;
+
+typedef struct VIDEORECAUDIOOUT
+{
+    PDMAUDIOHSTSTRMOUT pHostVoiceOut;
+    uint64_t old_ticks;
+    uint64_t cSamplesSentPerSec;
+} VIDEORECAUDIOOUT, *PVIDEORECAUDIOOUT;
+
+static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
+{
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+/** @todo Replace this with drvAudioHlpPcmPropsFromCfg(). */
+static int drvAudioVideoRecPcmInitInfo(PDMPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
+{
+    int rc = VINF_SUCCESS;
+
+    uint8_t cBits = 8, cShift = 0;
+    bool fSigned = false;
+
+    switch (as->enmFormat)
+    {
+        case AUD_FMT_S8:
+            fSigned = 1;
+        case AUD_FMT_U8:
+            break;
+
+        case AUD_FMT_S16:
+            fSigned = 1;
+        case AUD_FMT_U16:
+            cBits = 16;
+            cShift = 1;
+            break;
+
+        case AUD_FMT_S32:
+            fSigned = 1;
+        case AUD_FMT_U32:
+            cBits = 32;
+            cShift = 2;
+            break;
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    pProps->uHz = as->uHz;
+    pProps->cBits = cBits;
+    pProps->fSigned = fSigned;
+    pProps->cChannels = as->cChannels;
+    pProps->cShift = (as->cChannels == 2) + cShift;
+    pProps->uAlign = (1 << pProps->cShift) - 1;
+    pProps->cbPerSec = pProps->uHz << pProps->cShift;
+    pProps->fSwapEndian = (as->enmEndianness != PDMAUDIOHOSTENDIANESS);
+
+    return rc;
+}
+
+/*
+ * Hard voice (playback)
+ */
+static int audio_pcm_hw_find_min_out (PPDMAUDIOHSTSTRMOUT hw, int *nb_livep)
+{
+    PPDMAUDIOGSTSTRMOUT sw;
+    PPDMAUDIOGSTSTRMOUT pIter;
+    int m = INT_MAX;
+    int nb_live = 0;
+
+    RTListForEach(&hw->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
+    {
+        sw = pIter;
+        if (sw->State.fActive || !sw->State.fEmpty)
+        {
+            m = RT_MIN (m, sw->cTotalSamplesWritten);
+            nb_live += 1;
+        }
+    }
+
+    *nb_livep = nb_live;
+    return m;
+}
+
+static int audio_pcm_hw_get_live_out2 (PPDMAUDIOHSTSTRMOUT hw, int *nb_live)
+{
+    int smin;
+
+    smin = audio_pcm_hw_find_min_out (hw, nb_live);
+
+    if (!*nb_live) {
+        return 0;
+    }
+    else
+    {
+        int live = smin;
+
+        if (live < 0 || live > hw->cSamples)
+        {
+            LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
+            return 0;
+        }
+        return live;
+    }
+}
+
+
+static int audio_pcm_hw_get_live_out (PPDMAUDIOHSTSTRMOUT hw)
+{
+    int nb_live;
+    int live;
+
+    live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
+    if (live < 0 || live > hw->cSamples)
+    {
+        LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
+        return 0;
+    }
+    return live;
+}
+
+/*
+ * Hard voice (capture)
+ */
+static int audio_pcm_hw_find_min_in (PPDMAUDIOHSTSTRMIN hw)
+{
+    PPDMAUDIOGSTSTRMIN pIter;
+    int m = hw->cTotalSamplesCaptured;
+
+    RTListForEach(&hw->lstGstStreamsIn, pIter, PDMAUDIOGSTSTRMIN, Node)
+    {
+        if (pIter->State.fActive)
+        {
+            m = RT_MIN (m, pIter->cTotalHostSamplesRead);
+        }
+    }
+    return m;
+}
+
+int audio_pcm_hw_get_live_in (PPDMAUDIOHSTSTRMIN hw)
+{
+    int live = hw->cTotalSamplesCaptured - audio_pcm_hw_find_min_in (hw);
+    if (live < 0 || live > hw->cSamples)
+    {
+        LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
+        return 0;
+    }
+    return live;
+}
+
+static inline void *advance (void *p, int incr)
+{
+    uint8_t *d = (uint8_t*)p;
+    return (d + incr);
+}
+
+static int vrdeReallocSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
+{
+    uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
+    if (cbBuffer > pVRDEVoice->cbSamplesBufferAllocated)
+    {
+        /** @todo r=andy Why not using RTMemReAlloc? */
+        if (pVRDEVoice->pvSamplesBuffer)
+        {
+            RTMemFree(pVRDEVoice->pvSamplesBuffer);
+            pVRDEVoice->pvSamplesBuffer = NULL;
+        }
+        pVRDEVoice->pvSamplesBuffer = RTMemAlloc(cbBuffer);
+        if (pVRDEVoice->pvSamplesBuffer)
+            pVRDEVoice->cbSamplesBufferAllocated = cbBuffer;
+        else
+            pVRDEVoice->cbSamplesBufferAllocated = 0;
+    }
+
+    return VINF_SUCCESS;
+}
+
+static int vrdeReallocRateAdjSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
+{
+    uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
+    if (cbBuffer > pVRDEVoice->cbRateBufferAllocated)
+    {
+        RTMemFree(pVRDEVoice->pvRateBuffer);
+        pVRDEVoice->pvRateBuffer = RTMemAlloc(cbBuffer);
+        if (pVRDEVoice->pvRateBuffer)
+            pVRDEVoice->cbRateBufferAllocated = cbBuffer;
+        else
+            pVRDEVoice->cbRateBufferAllocated = 0;
+    }
+
+    return VINF_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * AudioVideoRec input section
+ *
+ ******************************************************************************/
+
+/*
+ * Callback to feed audio input buffer. Samples format is be the same as
+ * in the voice. The caller prepares st_sample_t.
+ *
+ * @param cbSamples Size of pvSamples array in bytes.
+ * @param pvSamples Points to an array of samples.
+ *
+ * @return IPRT status code.
+ */
+static int vrdeRecordingCallback(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cbSamples, const void *pvSamples)
+{
+    int rc = VINF_SUCCESS;
+    size_t csWritten = 0;
+
+    Assert((cbSamples % sizeof(PDMAUDIOSAMPLE)) == 0);
+
+    if (!pVRDEVoice->fIsInit)
+        return VINF_SUCCESS;
+
+    /* If nothing is pending return immediately. */
+    if (cbSamples == 0)
+        return VINF_SUCCESS;
+
+    /* How much space is free in the ring buffer? */
+    size_t csAvail = RTCircBufFree(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE); /* bytes -> samples */
+
+    /* How much space is used in the audio buffer. Use the smaller size of the too. */
+    csAvail = RT_MIN(csAvail, cbSamples / sizeof(PDMAUDIOSAMPLE));
+
+    /* Iterate as long as data is available. */
+    while (csWritten < csAvail)
+    {
+        /* How much is left? */
+        size_t csToWrite = csAvail - csWritten;
+        size_t cbToWrite = csToWrite * sizeof(PDMAUDIOSAMPLE);
+
+        /* Try to acquire the necessary space from the ring buffer. */
+        void *pcDst;
+        RTCircBufAcquireWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite, &pcDst, &cbToWrite);
+
+        /* How much do we get? */
+        csToWrite = cbToWrite / sizeof(PDMAUDIOSAMPLE);
+
+        /* Copy the data from the audio buffer to the ring buffer in PVRDEVoice. */
+        if (csToWrite)
+        {
+            memcpy(pcDst, (uint8_t *)pvSamples + (csWritten * sizeof(PDMAUDIOSAMPLE)), cbToWrite);
+            csWritten += csToWrite;
+        }
+
+        /* Release the ring buffer, so the main thread could start reading this data. */
+        RTCircBufReleaseWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite);
+
+        if (RT_UNLIKELY(csToWrite == 0))
+            break;
+    }
+
+    LogFlowFunc(("Finished writing buffer with %RU32 samples (%RU32 bytes)\n",
+                 csWritten, csWritten * sizeof(PDMAUDIOSAMPLE)));
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut, PPDMAUDIOSTREAMCFG pCfg)
+{
+    LogFlowFuncEnter();
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+
+    PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
+    pHostVoiceOut->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
+
+    return drvAudioVideoRecPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, pCfg);
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn, PPDMAUDIOSTREAMCFG pCfg)
+{
+    LogFlowFuncEnter();
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+
+    PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
+    pHostVoiceIn->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
+
+    return drvAudioVideoRecPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, pCfg);
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
+                                                   uint32_t *pcSamplesCaptured)
+{
+    /** @todo Take care of the size of the buffer allocated to pHostVoiceIn. */
+    PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
+
+    /* use this from DrvHostCoreAudio.c */
+    if (ASMAtomicReadU32(&pVRDEVoice->status) != CA_STATUS_INIT)
+    {
+        LogFlowFunc(("VRDE voice not initialized\n"));
+
+        *pcSamplesCaptured = 0;
+        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
+    }
+
+    /* how much space is used in the ring buffer in pRecordedVocieBuf with pAudioVideoRec . Bytes-> samples*/
+    size_t cSamplesRingBuffer = RTCircBufUsed(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE);
+
+    /* How much space is available in the mix buffer. Use the smaller size of the too. */
+    cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples -
+                                audio_pcm_hw_get_live_in (&pVRDEVoice->pHostVoiceIn)));
+
+    LogFlowFunc(("Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
+                 cSamplesRingBuffer * sizeof(PDMAUDIOSAMPLE)));
+
+    /* Iterate as long as data is available */
+    size_t cSamplesRead = 0;
+    while (cSamplesRead < cSamplesRingBuffer)
+    {
+        /* How much is left? Split request at the end of our samples buffer. */
+        size_t cSamplesToRead = RT_MIN(cSamplesRingBuffer - cSamplesRead,
+                                       (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples - pVRDEVoice->pHostVoiceIn.offSamplesWritten));
+        size_t cbToRead = cSamplesToRead * sizeof(PDMAUDIOSAMPLE);
+        LogFlowFunc(("Try reading %zu samples (%zu bytes)\n", cSamplesToRead, cbToRead));
+
+        /* Try to acquire the necessary block from the ring buffer. Remeber in fltRecrodCallback we
+         * we are filling this buffer with the audio data available from VRDP. Here we are reading it
+         */
+        /*todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
+         * filling is in separate thread and the reading of that buffer is in separate thread
+         */
+        void *pvSrc;
+        RTCircBufAcquireReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead, &pvSrc, &cbToRead);
+
+        /* How much to we get? */
+        cSamplesToRead = cbToRead / sizeof(PDMAUDIOSAMPLE);
+        LogFlowFunc(("AuderVRDE: There are %d samples (%d bytes) available\n", cSamplesToRead, cbToRead));
+
+        /* Break if nothing is used anymore. */
+        if (cSamplesToRead)
+        {
+            /* Copy the data from our ring buffer to the mix buffer. */
+            PPDMAUDIOSAMPLE psDst = pVRDEVoice->pHostVoiceIn.paSamples + pVRDEVoice->pHostVoiceIn.offSamplesWritten;
+            memcpy(psDst, pvSrc, cbToRead);
+        }
+
+        /* Release the read buffer, so it could be used for new data. */
+        RTCircBufReleaseReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead);
+
+        if (!cSamplesToRead)
+            break;
+
+        pVRDEVoice->pHostVoiceIn.offSamplesWritten = (pVRDEVoice->pHostVoiceIn.offSamplesWritten + cSamplesToRead)
+                                              % pVRDEVoice->pHostVoiceIn.cSamples;
+
+        /* How much have we reads so far. */
+        cSamplesRead += cSamplesToRead;
+    }
+
+    LogFlowFunc(("Finished reading buffer with %zu samples (%zu bytes)\n",
+                 cSamplesRead, cSamplesRead * sizeof(PDMAUDIOSAMPLE)));
+
+    *pcSamplesCaptured = cSamplesRead;
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut,
+                                                 uint32_t *pcSamplesPlayed)
+{
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+    PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
+
+    /*
+     * Just call the VRDP server with the data.
+     */
+    int live = audio_pcm_hw_get_live_out(pHostVoiceOut);
+    uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
+    uint64_t ticks = now  - pVRDEVoiceOut->old_ticks;
+    uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
+
+    int cSamplesPlayed = (int)((2 * ticks * pHostVoiceOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
+    if (cSamplesPlayed < 0)
+        cSamplesPlayed = live;
+
+    pHostVoiceOut->Props.cBits = 128; /** @todo Make this configurable (or at least a define)? */
+    VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHostVoiceOut->Props.uHz,
+                                                 pHostVoiceOut->Props.cChannels,
+                                                 pHostVoiceOut->Props.cBits, /* bits per sample */
+                                                 !pHostVoiceOut->Props.fSigned);
+
+    LogFlowFunc(("freq=%d, chan=%d, cBits = %d, fsigned = %d, cSamples=%d format=%d\n",
+                 pHostVoiceOut->Props.uHz, pHostVoiceOut->Props.cChannels,
+                 pHostVoiceOut->Props.cBits, pHostVoiceOut->Props.fSigned,
+                 pHostVoiceOut->cSamples, format));
+
+    pVRDEVoiceOut->old_ticks = now;
+    int cSamplesToSend = RT_MIN(live, cSamplesPlayed);
+
+    if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSamples)
+    {
+        /* send the samples till the end of pHostStereoSampleBuf */
+        pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
+                                                   (pHostVoiceOut->cSamples - pHostVoiceOut->cOffSamplesRead), format);
+        /*pHostStereoSampleBuff already has the samples which exceeded its space. They have overwriten the old
+         * played sampled starting from offset 0. So based on the number of samples that we had to play,
+         * read the number of samples from offset 0 .
+         */
+        pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[0],
+                                                   (cSamplesToSend - (pHostVoiceOut->cSamples -
+                                                                      pHostVoiceOut->cOffSamplesRead)),
+                                                   format);
+    }
+    else
+    {
+        pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
+                                                   cSamplesToSend, format);
+    }
+
+    pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSamples;
+
+    *pcSamplesPlayed = cSamplesToSend;
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN hw)
+{
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+    LogFlowFuncEnter();
+    pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut)
+{
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT hw,
+                                                    PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
+                                                   PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
+
+    /* Initialize  VRDEVoice and return to VRDP server which returns this struct back to us
+     * in the form void * pvContext
+     */
+    PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
+    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+
+    /* initialize only if not already done */
+    if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
+    {
+        //@todo if (!pVRDEVoice->fIsInit)
+        //    RTCircBufReset(pVRDEVoice->pRecordedVoiceBuf);
+        pVRDEVoice->fIsInit = 1;
+        pVRDEVoice->pHostVoiceIn = *pHostVoiceIn;
+        pVRDEVoice->cBytesPerFrame = 1;
+        pVRDEVoice->uFrequency = 0;
+        pVRDEVoice->rate = NULL;
+        pVRDEVoice->cbSamplesBufferAllocated = 0;
+        pVRDEVoice->pvRateBuffer = NULL;
+        pVRDEVoice->cbRateBufferAllocated = 0;
+
+        pVRDEVoice->pHostVoiceIn.cSamples = 2048;
+        /* Initialize the hardware info section with the audio settings */
+
+        ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
+
+        /* Create the internal ring buffer. */
+        RTCircBufCreate(&pVRDEVoice->pRecordedVoiceBuf,
+                        pVRDEVoice->pHostVoiceIn.cSamples * sizeof(PDMAUDIOSAMPLE));
+
+        if (!RT_VALID_PTR(pVRDEVoice->pRecordedVoiceBuf))
+        {
+            LogRel(("Failed to create internal ring buffer\n"));
+            return  VERR_NO_MEMORY;
+        }
+
+        ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
+        return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSamples,
+                                                             pHostVoiceIn->Props.uHz,
+                                                             pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
+    }
+    else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
+    {
+        pVRDEVoice->fIsInit = 0;
+        ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_UNINIT);
+        RTCircBufDestroy(pVRDEVoice->pRecordedVoiceBuf);
+        pVRDEVoice->pRecordedVoiceBuf = NULL;
+        ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_UNINIT);
+        pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
+    }
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pAudioConf)
+{
+    LogFlowFunc(("pAudioConf=%p\n", pAudioConf));
+
+    pAudioConf->cbStreamOut = sizeof(VIDEORECAUDIOOUT);
+    pAudioConf->cbStreamIn = sizeof(VIDEORECAUDIOIN);
+    pAudioConf->cMaxHstStrmsOut = 1;
+    pAudioConf->cMaxHstStrmsIn = 1;
+
+    return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    NOREF(pInterface);
+}
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVAUDIOVIDEOREC  pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+    return NULL;
+}
+
+AudioVideoRec::AudioVideoRec(Console *pConsole)
+    : mpDrv(NULL),
+      mParent(pConsole)
+{
+}
+
+AudioVideoRec::~AudioVideoRec(void)
+{
+    if (mpDrv)
+    {
+        mpDrv->pAudioVideoRec = NULL;
+        mpDrv = NULL;
+    }
+}
+
+int AudioVideoRec::handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept)
+{
+    LogFlowThisFunc(("fIntercept=%RTbool\n", fIntercept));
+    return VINF_SUCCESS;
+}
+
+int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels,
+                                                            int cBits, bool fUnsigned)
+{
+    int bitIdx;
+    PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
+    LogFlowFunc(("handleVRDPCmdInputEventBegin\n"));
+    /* Prepare a format convertion for the actually used format. */
+    pVRDEVoice->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
+    if (cBits == 16)
+    {
+        bitIdx = 1;
+    }
+    else if (cBits == 32)
+    {
+        bitIdx = 2;
+    }
+    else
+    {
+        bitIdx = 0;
+    }
+
+    //PPDMIAUDIOCONNECTOR pPort = server->mConsole->getAudioVideoRec()->getDrvAudioPort();
+    /* Call DrvAudio interface to get the t_sample type conversion function */
+    /*mpDrv->pUpPort->pfnConvDevFmtToStSample(mpDrv->pUpPort,
+                                            (cChannels == 2) ? 1 : 0,
+                                            !fUnsigned, 0, bitIdx,
+                                            pVRDEVoice->convAudioDevFmtToStSampl);*/
+    if (pVRDEVoice->convAudioDevFmtToStSampl)
+    {
+        LogFlowFunc(("Failed to get the conversion function \n"));
+    }
+    LogFlowFunc(("Required freq as requested by VRDP Server = %d\n", iSampleHz));
+    //if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
+    {
+        /* @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
+        /*mpDrv->pUpPort->pfnPrepareAudioConversion(mpDrv->pUpPort, iSampleHz,
+                                                  pVRDEVoice->pHostVoiceIn.Props.uFrequency,
+                                                  &pVRDEVoice->rate);*/
+        pVRDEVoice->uFrequency = iSampleHz;
+        LogFlowFunc(("pVRDEVoice assigned requested freq =%d\n", pVRDEVoice->uFrequency));
+    }
+    return VINF_SUCCESS;
+}
+
+/*
+ * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
+ *            drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
+ */
+int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData)
+{
+    PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
+    PPDMAUDIOSAMPLE pHostStereoSampleBuf; /* target sample buffer */
+    PPDMAUDIOSAMPLE pConvertedSampleBuf; /* samples adjusted for rate */
+    uint32_t cSamples = cbData / pVRDEVoice->cBytesPerFrame; /* Count of samples */
+    void * pTmpSampleBuf = NULL;
+    uint32_t cConvertedSamples; /* samples adjusted for rate */
+    uint32_t cbSamples = 0; /* count of bytes occupied by samples */
+    int rc = VINF_SUCCESS;
+
+    LogFlowFunc(("handleVRDPCmdInputEventData cbData = %d, bytesperfram=%d\n",
+              cbData, pVRDEVoice->cBytesPerFrame));
+
+    vrdeReallocSampleBuf(pVRDEVoice, cSamples);
+    pHostStereoSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvSamplesBuffer;
+    pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &videorec_nominal_volume);
+
+    /* count of rate adjusted samples */
+    pVRDEVoice->uFrequency = 22100; /* @todo handle this. How pVRDEVoice will get proper value */
+    cConvertedSamples = (cSamples * pVRDEVoice->pHostVoiceIn.Props.uHz) / pVRDEVoice->uFrequency;
+    vrdeReallocRateAdjSampleBuf(pVRDEVoice, cConvertedSamples);
+
+    pConvertedSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvRateBuffer;
+    if (pConvertedSampleBuf)
+    {
+        uint32_t cSampleSrc = cSamples;
+        uint32_t cSampleDst = cConvertedSamples;
+        /*mpDrv->pUpPort->pfnDoRateConversion(mpDrv->pUpPort, pVRDEVoice->rate, pHostStereoSampleBuf,
+                                            pConvertedSampleBuf, &cSampleSrc, &cConvertedSamples);*/
+        pTmpSampleBuf = pConvertedSampleBuf;
+        cbSamples =  cConvertedSamples * sizeof(PDMAUDIOSAMPLE);
+    }
+
+    if (cbSamples)
+        rc = vrdeRecordingCallback(pVRDEVoice, cbSamples, pTmpSampleBuf);
+
+    return rc;
+}
+
+/*
+ * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
+ *            drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
+ */
+int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext)
+{
+    LogFlowFuncEnter();
+
+    PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
+    AssertPtrReturn(pVRDEVoice, VERR_INVALID_POINTER);
+
+    /* The caller will not use this context anymore. */
+    if (pVRDEVoice->rate)
+    {
+        //mpDrv->pUpPort->pfnEndAudioConversion(mpDrv->pUpPort, pVRDEVoice->rate);
+    }
+
+    if (pVRDEVoice->pvSamplesBuffer)
+    {
+        RTMemFree(pVRDEVoice->pvSamplesBuffer);
+        pVRDEVoice->pvSamplesBuffer = NULL;
+    }
+
+    if (pVRDEVoice->pvRateBuffer)
+    {
+        RTMemFree(pVRDEVoice->pvRateBuffer);
+        pVRDEVoice->pvRateBuffer = NULL;
+    }
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Construct a VRDE audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+/* static */
+DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
+    LogRel(("Audio: Initializing VRDE driver\n"));
+    LogFlowFunc(("fFlags=0x%x\n", fFlags));
+
+    /* we save the address of AudioVideoRec in Object node in CFGM tree and address of VRDP server in
+     * ObjectVRDPServer node. So presence of both is necessary.
+     */
+    //if (!CFGMR3AreValuesValid(pCfg, "Object\0") || !CFGMR3AreValuesValid(pCfg, "ObjectVRDPServer\0"))
+    //   return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
+    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
+                    ("Configuration error: Not possible to attach anything to this driver!\n"),
+                    VERR_PDM_DRVINS_NO_ATTACH);
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
+
+    /* Get VRDPServer pointer. */
+    void *pvUser;
+    int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
+    if (RT_FAILURE(rc))
+    {
+        AssertMsgFailed(("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc));
+        return rc;
+    }
+
+    /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVideoRec. */
+    pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
+
+    pvUser = NULL;
+    rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
+    if (RT_FAILURE(rc))
+    {
+        AssertMsgFailed(("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc));
+        return rc;
+    }
+
+    pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
+    pThis->pAudioVideoRec->mpDrv = pThis;
+
+    /*
+     * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
+     * Described in CFGM tree.
+     */
+    pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
+    if (!pThis->pUpPort)
+    {
+        AssertMsgFailed(("Configuration error: No upper interface specified!\n"));
+        return VERR_PDM_MISSING_INTERFACE_ABOVE;
+    }
+
+    return VINF_SUCCESS;
+}
+
+/* static */
+DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
+{
+    LogFlowFuncEnter();
+}
+
+/**
+ * VRDE audio driver registration record.
+ */
+const PDMDRVREG AudioVideoRec::DrvReg =
+{
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "AudioVideoRec",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Audio driver for video recording",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVAUDIOVIDEOREC),
+    /* pfnConstruct */
+    AudioVideoRec::drvConstruct,
+    /* pfnDestruct */
+    AudioVideoRec::drvDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
diff --git a/src/VBox/Main/src-client/GuestProcessImpl.cpp b/src/VBox/Main/src-client/GuestProcessImpl.cpp
index 11e8e91..41d81df 100644
--- a/src/VBox/Main/src-client/GuestProcessImpl.cpp
+++ b/src/VBox/Main/src-client/GuestProcessImpl.cpp
@@ -2254,7 +2254,7 @@ int GuestProcessTool::i_waitEx(uint32_t fFlags, GuestProcessStreamBlock *pStrmBl
         vrc = i_getCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut);
         if (RT_SUCCESS(vrc))
             return vrc;
-        /* else do the the waiting below. */
+        /* else do the waiting below. */
     }
 
     /* Do the waiting. */
diff --git a/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
index 9edde02..5ae5fda 100644
--- a/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
+++ b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
@@ -34,6 +34,11 @@
 
 #include <linux/limits.h>
 
+/* Workaround for <sys/cdef.h> defining __flexarr to [] which beats us in
+ * struct inotify_event (char name __flexarr). */
+#include <sys/cdefs.h>
+#undef __flexarr
+#define __flexarr [0]
 #include <sys/inotify.h>
 #include <sys/types.h>
 #include <sys/socket.h>
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp
index 7cd1862..bab5818 100644
--- a/src/VBox/Main/xml/Settings.cpp
+++ b/src/VBox/Main/xml/Settings.cpp
@@ -3439,21 +3439,25 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode,
     {
         enmAttachmentType = NetworkAttachmentType_Bridged;
 
-        elmMode.getAttributeValue("name", nic.strBridgedName);  // optional bridged interface name
+        // optional network name, cannot be required or we have trouble with
+        // settings which are saved before configuring the network name
+        elmMode.getAttributeValue("name", nic.strBridgedName);
     }
     else if (elmMode.nameEquals("InternalNetwork"))
     {
         enmAttachmentType = NetworkAttachmentType_Internal;
 
-        if (!elmMode.getAttributeValue("name", nic.strInternalNetworkName))    // required network name
-            throw ConfigFileError(this, &elmMode, N_("Required InternalNetwork/@name element is missing"));
+        // optional network name, cannot be required or we have trouble with
+        // settings which are saved before configuring the network name
+        elmMode.getAttributeValue("name", nic.strInternalNetworkName);
     }
     else if (elmMode.nameEquals("HostOnlyInterface"))
     {
         enmAttachmentType = NetworkAttachmentType_HostOnly;
 
-        if (!elmMode.getAttributeValue("name", nic.strHostOnlyName))    // required network name
-            throw ConfigFileError(this, &elmMode, N_("Required HostOnlyInterface/@name element is missing"));
+        // optional network name, cannot be required or we have trouble with
+        // settings which are saved before configuring the network name
+        elmMode.getAttributeValue("name", nic.strHostOnlyName);
     }
     else if (elmMode.nameEquals("GenericInterface"))
     {
@@ -3481,11 +3485,14 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode,
     {
         enmAttachmentType = NetworkAttachmentType_NATNetwork;
 
-        if (!elmMode.getAttributeValue("name", nic.strNATNetworkName))    // required network name
-            throw ConfigFileError(this, &elmMode, N_("Required NATNetwork/@name element is missing"));
+        // optional network name, cannot be required or we have trouble with
+        // settings which are saved before configuring the network name
+        elmMode.getAttributeValue("name", nic.strNATNetworkName);
     }
     else if (elmMode.nameEquals("VDE"))
     {
+        // inofficial hack (VDE networking was never part of the official
+        // settings, so it's not mentioned in VirtualBox-settings.xsd)
         enmAttachmentType = NetworkAttachmentType_Generic;
 
         com::Utf8Str strVDEName;
diff --git a/src/VBox/Main/xml/VirtualBox-settings.xsd b/src/VBox/Main/xml/VirtualBox-settings.xsd
index f6a8e35..8145cd9 100644
--- a/src/VBox/Main/xml/VirtualBox-settings.xsd
+++ b/src/VBox/Main/xml/VirtualBox-settings.xsd
@@ -936,19 +936,19 @@
 </xsd:complexType>
 
 <xsd:complexType name="TNetNATNetwork">
-  <xsd:attribute name="name" type="xsd:string" use="required"/>
+  <xsd:attribute name="name" type="xsd:string"/>
 </xsd:complexType>
 
 <xsd:complexType name="TNetBridged">
-  <xsd:attribute name="name" type="xsd:string" use="required"/>
+  <xsd:attribute name="name" type="xsd:string"/>
 </xsd:complexType>
 
 <xsd:complexType name="TNetInternal">
-  <xsd:attribute name="name" type="xsd:string" use="required"/>
+  <xsd:attribute name="name" type="xsd:string"/>
 </xsd:complexType>
 
 <xsd:complexType name="TNetHostOnly">
-  <xsd:attribute name="name" type="xsd:string" use="required"/>
+  <xsd:attribute name="name" type="xsd:string"/>
 </xsd:complexType>
 
 <xsd:complexType name="TNetGeneric">
diff --git a/src/VBox/NetworkServices/NAT/RTWinPoll.cpp b/src/VBox/NetworkServices/NAT/RTWinPoll.cpp
index f754b57..babd9d9 100644
--- a/src/VBox/NetworkServices/NAT/RTWinPoll.cpp
+++ b/src/VBox/NetworkServices/NAT/RTWinPoll.cpp
@@ -40,12 +40,16 @@ RTWinPoll(struct pollfd *pFds, unsigned int nfds, int timeout, int *pNready)
     {
         g_hNetworkEvent = WSACreateEvent();
         AssertReturn(g_hNetworkEvent != WSA_INVALID_EVENT, VERR_INTERNAL_ERROR);
+
+        /* XXX: provide feedback that env vars are set correctly */
+        LogRel2(("NAT_SERVICE LogRel2 enabled\n"));
     }
 
     for (unsigned int i = 0; i < nfds; ++i)
     {
         long eventMask = 0;
         short pollEvents = pFds[i].events;
+        int err;
 
         /* clean revents */
         pFds[i].revents = 0;
@@ -75,7 +79,15 @@ RTWinPoll(struct pollfd *pFds, unsigned int nfds, int timeout, int *pNready)
          * This is "moral" equivalent to POLLHUP.
          */
         eventMask |= FD_CLOSE;
-        WSAEventSelect(pFds[i].fd, g_hNetworkEvent, eventMask);
+
+        err = WSAEventSelect(pFds[i].fd, g_hNetworkEvent, eventMask);
+        if (err != 0)
+        {
+            err = WSAGetLastError();
+            LogRel2(("sock %d: WSAEventSelect: %R[sockerr]\n", pFds[i].fd, err));
+
+            pFds[i].revents = POLLNVAL;
+        }
     }
 
     DWORD index = WSAWaitForMultipleEvents(1,
@@ -99,15 +111,30 @@ RTWinPoll(struct pollfd *pFds, unsigned int nfds, int timeout, int *pNready)
         if (pFds[i].fd == INVALID_SOCKET)
             continue;
 
+        if (pFds[i].revents == POLLNVAL)
+        {
+            ++nready;
+            continue;
+        }
+
+
         RT_ZERO(NetworkEvents);
 
         err = WSAEnumNetworkEvents(pFds[i].fd,
                                    g_hNetworkEvent,
                                    &NetworkEvents);
 
-        if (err == SOCKET_ERROR)
+        if (err != 0)
+            err = WSAGetLastError();
+
+        /* disociate socket from event */
+        WSAEventSelect(pFds[i].fd, g_hNetworkEvent, 0);
+
+        if (err != 0)
         {
-            if (WSAGetLastError() == WSAENOTSOCK)
+            LogRel2(("sock %d: WSAEnumNetworkEvents: %R[sockerr]\n", pFds[i].fd, err));
+
+            if (err == WSAENOTSOCK)
             {
                 pFds[i].revents = POLLNVAL;
                 ++nready;
@@ -115,9 +142,6 @@ RTWinPoll(struct pollfd *pFds, unsigned int nfds, int timeout, int *pNready)
             continue;
         }
 
-        /* deassociate socket with event */
-        WSAEventSelect(pFds[i].fd, g_hNetworkEvent, 0);
-
 #define WSA_TO_POLL(_wsaev, _pollev)                                    \
         do {                                                            \
             if (NetworkEvents.lNetworkEvents & (_wsaev)) {              \
diff --git a/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp b/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp
index 1307262..7551407 100644
--- a/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp
+++ b/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp
@@ -1016,7 +1016,10 @@ int VBoxNetLwipNAT::processFrame(void *pvFrame, size_t cbFrame)
 
     struct pbuf *p = pbuf_alloc(PBUF_RAW, (u16_t)cbFrame + ETH_PAD_SIZE, PBUF_POOL);
     if (RT_UNLIKELY(p == NULL))
+    {
+        LogRel2(("pbuf_alloc failed\n"));
         return VERR_NO_MEMORY;
+    }
 
     /*
      * The code below is inlined version of:
diff --git a/src/VBox/NetworkServices/NAT/proxy_pollmgr.c b/src/VBox/NetworkServices/NAT/proxy_pollmgr.c
index 6431c98..f41e5db 100644
--- a/src/VBox/NetworkServices/NAT/proxy_pollmgr.c
+++ b/src/VBox/NetworkServices/NAT/proxy_pollmgr.c
@@ -420,6 +420,11 @@ pollmgr_loop(void)
                 }
 # endif /* LWIP_PROXY_DEBUG / DEBUG */
 #endif
+                /* XXX: temporary instrumentation for ticketref:13899 */
+                if (revents == POLLNVAL) {
+                    LogRel2(("sock %d: POLLNVAL handler=%p\n", fd, handler));
+                }
+
                 nevents = (*handler->callback)(handler, fd, revents);
             }
             else {
diff --git a/src/VBox/NetworkServices/NAT/pxtcp.c b/src/VBox/NetworkServices/NAT/pxtcp.c
index cd2482f..c45a382 100644
--- a/src/VBox/NetworkServices/NAT/pxtcp.c
+++ b/src/VBox/NetworkServices/NAT/pxtcp.c
@@ -1607,6 +1607,10 @@ pxtcp_pcb_forward_outbound(struct pxtcp *pxtcp, struct pbuf *p)
             DPRINTF2(("forward_outbound: pxtcp %p, pcb %p: %R[sockerr]\n",
                       (void *)pxtcp, (void *)pcb, sockerr));
 
+            /* XXX: temporary instrumentation for ticketref:13899 */
+            LogRel2(("forward_outbound: sock %d, pxtcp %p, pcb %p: %R[sockerr]\n",
+                    pxtcp->sock, (void *)pxtcp, (void *)pcb, sockerr));
+
             pxtcp_pcb_dissociate(pxtcp);
 
             tcp_abort(pcb);
diff --git a/src/VBox/Runtime/common/crypto/pemfile.cpp b/src/VBox/Runtime/common/crypto/pemfile.cpp
index 806c2b2..a944c71 100644
--- a/src/VBox/Runtime/common/crypto/pemfile.cpp
+++ b/src/VBox/Runtime/common/crypto/pemfile.cpp
@@ -324,6 +324,7 @@ RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead)
             pFree->pszPreamble = NULL;
             pFree->cchPreamble = 0;
         }
+        RTMemFree(pFree);
     }
     return VINF_SUCCESS;
 }
diff --git a/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp b/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp
index 7a08388..3eaad26 100644
--- a/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp
+++ b/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp
@@ -295,7 +295,7 @@ static int rtCrPkcs7VerifySignerInfoAuthAttribs(PCRTCRPKCS7SIGNERINFO pSignerInf
                             "Missing authenticated message-digest attribute.");
 
     /*
-     * Calculate the digest of the the authenticated attributes for use in the
+     * Calculate the digest of the authenticated attributes for use in the
      * signature validation.
      */
     if (   pSignerInfo->DigestAlgorithm.Parameters.enmType != RTASN1TYPE_NULL
diff --git a/src/VBox/Runtime/common/crypto/spc-template.h b/src/VBox/Runtime/common/crypto/spc-template.h
index 2849ecf..f2d2703 100644
--- a/src/VBox/Runtime/common/crypto/spc-template.h
+++ b/src/VBox/Runtime/common/crypto/spc-template.h
@@ -127,7 +127,7 @@ RTASN1TMPL_END_PCHOICE();
  * SPC PE Image Data.
  *
  * Note! This is not correctly declared in available specifications. The file
- *       member is tagged.  Seeing the the '--#public--' comment in the specs,
+ *       member is tagged.  Seeing the '--#public--' comment in the specs,
  *       one can't only guess that there are other alternatives in that part
  *       of the structure that microsoft does not wish to document.
  */
diff --git a/src/VBox/Runtime/common/crypto/x509-certpaths.cpp b/src/VBox/Runtime/common/crypto/x509-certpaths.cpp
index ddcbee2..51e3e3d 100644
--- a/src/VBox/Runtime/common/crypto/x509-certpaths.cpp
+++ b/src/VBox/Runtime/common/crypto/x509-certpaths.cpp
@@ -2487,7 +2487,7 @@ static bool rtCrX509CpvWrapUp(PRTCRX509CERTPATHSINT pThis, PRTCRX509CERTPATHNODE
 /**
  * Worker that validates one path.
  *
- * This implements the the algorithm in RFC-5280, section 6.1, with exception of
+ * This implements the algorithm in RFC-5280, section 6.1, with exception of
  * the CRL checks in 6.1.3.a.3.
  *
  * @returns success indicator.
diff --git a/src/VBox/Runtime/common/err/errmsgxpcom.cpp b/src/VBox/Runtime/common/err/errmsgxpcom.cpp
index 4311c3e..f874d01 100644
--- a/src/VBox/Runtime/common/err/errmsgxpcom.cpp
+++ b/src/VBox/Runtime/common/err/errmsgxpcom.cpp
@@ -105,6 +105,7 @@ static const RTCOMERRMSG  g_aStatusMsgs[] =
     MY_ERR("NS_ERROR_FILE_DIR_NOT_EMPTY",           "NS_ERROR_FILE_DIR_NOT_EMPTY",                  UINT32_C(0x80520014)),
     MY_ERR("NS_ERROR_FILE_ACCESS_DENIED",           "NS_ERROR_FILE_ACCESS_DENIED",                  UINT32_C(0x80520015)),
     MY_ERR("NS_SUCCESS_FILE_DIRECTORY_EMPTY",       "NS_SUCCESS_FILE_DIRECTORY_EMPTY",              UINT32_C(0x00520001)),
+    MY_ERR("NS_ERROR_SOCKET_FAIL",                  "IPC daemon socket error",                      UINT32_C(0xc1f30200)), /* new XPCOM error code */
 
 #if defined(VBOX) && !defined(IN_GUEST) && !defined(DOXYGEN_RUNNING)
 # include "errmsgvboxcomdata.h"
diff --git a/src/VBox/Runtime/common/misc/uri.cpp b/src/VBox/Runtime/common/misc/uri.cpp
index 3364a56..28b970f 100644
--- a/src/VBox/Runtime/common/misc/uri.cpp
+++ b/src/VBox/Runtime/common/misc/uri.cpp
@@ -1006,7 +1006,7 @@ RTDECL(int) RTUriFilePathEx(const char *pszUri, uint32_t fPathStyle, char **ppsz
      *     - file://///cifsserver.dev/systemshare/System32\kernel32.dll
      *              \---path--------------------------------------------/
      *
-     * The the two unescaped variants shouldn't be handed to rtUriParse, which
+     * The two unescaped variants shouldn't be handed to rtUriParse, which
      * is good as we cannot actually handle the one marked by (**).  So, handle
      * those two special when parsing.
      */
diff --git a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
index 4cf93c6..e43712d 100644
--- a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
@@ -1049,8 +1049,14 @@ DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3P
         if (R0Process == RTR0ProcHandleSelf())
             rc = get_user_pages(R3Ptr,                  /* Where from. */
                                 cPages,                 /* How many pages. */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+                                fWrite ? FOLL_WRITE |   /* Write to memory. */
+                                         FOLL_FORCE     /* force write access. */
+                                       : 0,             /* Write to memory. */
+# else
                                 fWrite,                 /* Write to memory. */
                                 fWrite,                 /* force write access. */
+# endif
                                 &pMemLnx->apPages[0],   /* Page array. */
                                 papVMAs);               /* vmas */
         /*
@@ -1063,8 +1069,14 @@ DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3P
                                 pTask->mm,              /* Whose pages. */
                                 R3Ptr,                  /* Where from. */
                                 cPages,                 /* How many pages. */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+                                fWrite ? FOLL_WRITE |   /* Write to memory. */
+                                         FOLL_FORCE     /* force write access. */
+                                       : 0,             /* Write to memory. */
+# else
                                 fWrite,                 /* Write to memory. */
                                 fWrite,                 /* force write access. */
+# endif
                                 &pMemLnx->apPages[0],   /* Page array. */
                                 papVMAs);               /* vmas */
 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) */
@@ -1072,8 +1084,14 @@ DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3P
                                 pTask->mm,              /* Whose pages. */
                                 R3Ptr,                  /* Where from. */
                                 cPages,                 /* How many pages. */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+                                fWrite ? FOLL_WRITE |   /* Write to memory. */
+                                         FOLL_FORCE     /* force write access. */
+                                       : 0,             /* Write to memory. */
+# else
                                 fWrite,                 /* Write to memory. */
                                 fWrite,                 /* force write access. */
+# endif
                                 &pMemLnx->apPages[0],   /* Page array. */
                                 papVMAs);               /* vmas */
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) */
diff --git a/src/VBox/Runtime/r3/win/mp-win.cpp b/src/VBox/Runtime/r3/win/mp-win.cpp
index 94cf53d..fd5fb34 100644
--- a/src/VBox/Runtime/r3/win/mp-win.cpp
+++ b/src/VBox/Runtime/r3/win/mp-win.cpp
@@ -175,7 +175,7 @@ static DECLCALLBACK(int32_t) rtMpWinInitOnce(void *pvUser)
     /*
      * Query group information, partitioning CPU IDs and CPU set indexes.
      *
-     * We ASSUME the the GroupInfo index is the same as the group number.
+     * We ASSUME the GroupInfo index is the same as the group number.
      *
      * We CANNOT ASSUME that the kernel CPU indexes are assigned in any given
      * way, though they usually are in group order by active processor.  So,
diff --git a/src/VBox/Runtime/tools/RTSignTool.cpp b/src/VBox/Runtime/tools/RTSignTool.cpp
index a01274f..6fa23e1 100644
--- a/src/VBox/Runtime/tools/RTSignTool.cpp
+++ b/src/VBox/Runtime/tools/RTSignTool.cpp
@@ -436,7 +436,15 @@ static RTEXITCODE HandleVerifyExeWorker(VERIFYEXESTATE *pState, const char *pszF
         rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo));
         if (RT_SUCCESS(rc))
             RTMsgInfo("'%s' is valid.\n", pszFilename);
-        else
+        else if (rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME)
+        {
+            RTTIMESPEC Now;
+            pState->uTimestamp = RTTimeSpecGetSeconds(RTTimeNow(&Now));
+            rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo));
+            if (RT_SUCCESS(rc))
+                RTMsgInfo("'%s' is valid now, but not at link time.\n", pszFilename);
+        }
+        if (RT_FAILURE(rc))
             RTMsgError("RTLdrVerifySignature failed on '%s': %Rrc - %s\n", pszFilename, rc, pStaticErrInfo->szMsg);
     }
     else
diff --git a/src/VBox/Storage/VDI.cpp b/src/VBox/Storage/VDI.cpp
index 1fae841..9eeb440 100644
--- a/src/VBox/Storage/VDI.cpp
+++ b/src/VBox/Storage/VDI.cpp
@@ -2615,6 +2615,13 @@ static DECLCALLBACK(int) vdiResize(void *pBackendData, uint64_t cbSize,
     PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
     int rc = VINF_SUCCESS;
 
+    /* Check size. Maximum 4PB-3M. No tricks with adjusting the 1M block size
+     * so far, which would extend the size. */
+    if (   !cbSize
+        || cbSize >= _1P * 4 - _1M * 3
+        || cbSize < VDI_IMAGE_DEFAULT_BLOCK_SIZE)
+        return VERR_VD_INVALID_SIZE;
+
     /*
      * Making the image smaller is not supported at the moment.
      * Resizing is also not supported for fixed size images and
@@ -2637,121 +2644,123 @@ static DECLCALLBACK(int) vdiResize(void *pBackendData, uint64_t cbSize,
         uint64_t cbBlockspaceNew = cBlocksNew * sizeof(VDIIMAGEBLOCKPOINTER); /** < Required space for the block array after the resize. */
         uint64_t offStartDataNew = RT_ALIGN_32(pImage->offStartBlocks + cbBlockspaceNew, VDI_DATA_ALIGN); /** < New start offset for block data after the resize */
 
-        if (   pImage->offStartData < offStartDataNew
-            && cBlocksAllocated > 0)
+        if (pImage->offStartData < offStartDataNew)
         {
-            /* Calculate how many sectors need to be relocated. */
-            uint64_t cbOverlapping = offStartDataNew - pImage->offStartData;
-            unsigned cBlocksReloc = cbOverlapping / getImageBlockSize(&pImage->Header);
-            if (cbOverlapping % getImageBlockSize(&pImage->Header))
-                cBlocksReloc++;
+            if (cBlocksAllocated > 0)
+            {
+                /* Calculate how many sectors need to be relocated. */
+                uint64_t cbOverlapping = offStartDataNew - pImage->offStartData;
+                unsigned cBlocksReloc = cbOverlapping / getImageBlockSize(&pImage->Header);
+                if (cbOverlapping % getImageBlockSize(&pImage->Header))
+                    cBlocksReloc++;
 
-            /* Since only full blocks can be relocated the new data start is
-             * determined by moving it block by block. */
-            cBlocksReloc = RT_MIN(cBlocksReloc, cBlocksAllocated);
-            offStartDataNew = pImage->offStartData;
+                /* Since only full blocks can be relocated the new data start is
+                 * determined by moving it block by block. */
+                cBlocksReloc = RT_MIN(cBlocksReloc, cBlocksAllocated);
+                offStartDataNew = pImage->offStartData;
 
-            /* Do the relocation. */
-            LogFlow(("Relocating %u blocks\n", cBlocksReloc));
+                /* Do the relocation. */
+                LogFlow(("Relocating %u blocks\n", cBlocksReloc));
 
-            /*
-             * Get the blocks we need to relocate first, they are appended to the end
-             * of the image.
-             */
-            void *pvBuf = NULL, *pvZero = NULL;
-            do
-            {
-                /* Allocate data buffer. */
-                pvBuf = RTMemAllocZ(pImage->cbTotalBlockData);
-                if (!pvBuf)
+                /*
+                 * Get the blocks we need to relocate first, they are appended to the end
+                 * of the image.
+                 */
+                void *pvBuf = NULL, *pvZero = NULL;
+                do
                 {
-                    rc = VERR_NO_MEMORY;
-                    break;
-                }
+                    /* Allocate data buffer. */
+                    pvBuf = RTMemAllocZ(pImage->cbTotalBlockData);
+                    if (!pvBuf)
+                    {
+                        rc = VERR_NO_MEMORY;
+                        break;
+                    }
 
-                /* Allocate buffer for overwriting with zeroes. */
-                pvZero = RTMemAllocZ(pImage->cbTotalBlockData);
-                if (!pvZero)
-                {
-                    rc = VERR_NO_MEMORY;
-                    break;
-                }
+                    /* Allocate buffer for overwriting with zeroes. */
+                    pvZero = RTMemAllocZ(pImage->cbTotalBlockData);
+                    if (!pvZero)
+                    {
+                        rc = VERR_NO_MEMORY;
+                        break;
+                    }
 
-                for (unsigned i = 0; i < cBlocksReloc; i++)
-                {
-                    /* Search the index in the block table. */
-                    for (unsigned idxBlock = 0; idxBlock < cBlocksOld; idxBlock++)
+                    for (unsigned i = 0; i < cBlocksReloc; i++)
                     {
-                        if (!pImage->paBlocks[idxBlock])
+                        /* Search the index in the block table. */
+                        for (unsigned idxBlock = 0; idxBlock < cBlocksOld; idxBlock++)
                         {
-                            /* Read data and append to the end of the image. */
-                            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
-                                                       offStartDataNew, pvBuf,
-                                                       pImage->cbTotalBlockData);
-                            if (RT_FAILURE(rc))
-                                break;
-
-                            uint64_t offBlockAppend;
-                            rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &offBlockAppend);
-                            if (RT_FAILURE(rc))
-                                break;
-
-                            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                        offBlockAppend, pvBuf,
-                                                        pImage->cbTotalBlockData);
-                            if (RT_FAILURE(rc))
-                                break;
-
-                            /* Zero out the old block area. */
-                            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
-                                                        offStartDataNew, pvZero,
-                                                        pImage->cbTotalBlockData);
-                            if (RT_FAILURE(rc))
-                                break;
-
-                            /* Update block counter. */
-                            pImage->paBlocks[idxBlock] = cBlocksAllocated - 1;
-
-                            /*
-                             * Decrease the block number of all other entries in the array.
-                             * They were moved one block to the front.
-                             * Doing it as a separate step iterating over the array again
-                             * because an error while relocating the block might end up
-                             * in a corrupted image otherwise.
-                             */
-                            for (unsigned idxBlock2 = 0; idxBlock2 < cBlocksOld; idxBlock2++)
+                            if (!pImage->paBlocks[idxBlock])
                             {
-                                if (   idxBlock2 != idxBlock
-                                    && IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[idxBlock2]))
-                                    pImage->paBlocks[idxBlock2]--;
+                                /* Read data and append to the end of the image. */
+                                rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
+                                                           offStartDataNew, pvBuf,
+                                                           pImage->cbTotalBlockData);
+                                if (RT_FAILURE(rc))
+                                    break;
+
+                                uint64_t offBlockAppend;
+                                rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &offBlockAppend);
+                                if (RT_FAILURE(rc))
+                                    break;
+
+                                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
+                                                            offBlockAppend, pvBuf,
+                                                            pImage->cbTotalBlockData);
+                                if (RT_FAILURE(rc))
+                                    break;
+
+                                /* Zero out the old block area. */
+                                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
+                                                            offStartDataNew, pvZero,
+                                                            pImage->cbTotalBlockData);
+                                if (RT_FAILURE(rc))
+                                    break;
+
+                                /* Update block counter. */
+                                pImage->paBlocks[idxBlock] = cBlocksAllocated - 1;
+
+                                /*
+                                 * Decrease the block number of all other entries in the array.
+                                 * They were moved one block to the front.
+                                 * Doing it as a separate step iterating over the array again
+                                 * because an error while relocating the block might end up
+                                 * in a corrupted image otherwise.
+                                 */
+                                for (unsigned idxBlock2 = 0; idxBlock2 < cBlocksOld; idxBlock2++)
+                                {
+                                    if (   idxBlock2 != idxBlock
+                                        && IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[idxBlock2]))
+                                        pImage->paBlocks[idxBlock2]--;
+                                }
+
+                                /* Continue with the next block. */
+                                break;
                             }
+                        }
 
-                            /* Continue with the next block. */
+                        if (RT_FAILURE(rc))
                             break;
-                        }
-                    }
 
-                    if (RT_FAILURE(rc))
-                        break;
+                        offStartDataNew += pImage->cbTotalBlockData;
+                    }
+                } while (0);
 
-                    offStartDataNew += pImage->cbTotalBlockData;
-                }
-            } while (0);
+                if (pvBuf)
+                    RTMemFree(pvBuf);
+                if (pvZero)
+                    RTMemFree(pvZero);
+            }
 
-            if (pvBuf)
-                RTMemFree(pvBuf);
-            if (pvZero)
-                RTMemFree(pvZero);
+            /*
+             * We need to update the new offsets for the image data in the out of memory
+             * case too because we relocated the blocks already.
+             */
+            pImage->offStartData = offStartDataNew;
+            setImageDataOffset(&pImage->Header, offStartDataNew);
         }
 
         /*
-         * We need to update the new offsets for the image data in the out of memory
-         * case too because we relocated the blocks already.
-         */
-        pImage->offStartData = offStartDataNew;
-        setImageDataOffset(&pImage->Header, offStartDataNew);
-
-        /*
          * Relocation done, expand the block array and update the header with
          * the new data.
          */
diff --git a/src/VBox/Storage/testcase/VDScriptInterp.cpp b/src/VBox/Storage/testcase/VDScriptInterp.cpp
index 8eca4b9..43fe436 100644
--- a/src/VBox/Storage/testcase/VDScriptInterp.cpp
+++ b/src/VBox/Storage/testcase/VDScriptInterp.cpp
@@ -368,7 +368,7 @@ DECLINLINE(int) vdScriptInterpreterPushForCtrlEntry(PVDSCRIPTINTERPCTX pThis, PV
         pCtrl->Ctrl.pAstNode    = &pStmt->Core;
         vdScriptStackPush(&pThis->StackCtrl);
 
-        /* Push the conditional first and the the initializer .*/
+        /* Push the conditional first and the initializer .*/
         rc = vdScriptInterpreterPushAstEntry(pThis, &pStmt->For.pExprCond->Core);
         if (RT_SUCCESS(rc))
         {
diff --git a/src/VBox/VMM/VMMAll/PGMAllHandler.cpp b/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
index 98efe16..21fca1e 100644
--- a/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
+++ b/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
@@ -122,9 +122,8 @@ VMMDECL(uint32_t) PGMHandlerPhysicalTypeRetain(PVM pVM, PGMPHYSHANDLERTYPE hType
 }
 
 
-
 /**
- * Register a access handler for a physical range.
+ * Creates a physical access handler.
  *
  * @returns VBox status code.
  * @retval  VINF_SUCCESS when successfully installed.
@@ -135,8 +134,6 @@ VMMDECL(uint32_t) PGMHandlerPhysicalTypeRetain(PVM pVM, PGMPHYSHANDLERTYPE hType
  *          one. A debug assertion is raised.
  *
  * @param   pVM             The cross context VM structure.
- * @param   GCPhys          Start physical address.
- * @param   GCPhysLast      Last physical address. (inclusive)
  * @param   hType           The handler type registration handle.
  * @param   pvUserR3        User argument to the R3 handler.
  * @param   pvUserR0        User argument to the R0 handler.
@@ -145,18 +142,102 @@ VMMDECL(uint32_t) PGMHandlerPhysicalTypeRetain(PVM pVM, PGMPHYSHANDLERTYPE hType
  *                          automatically relocated.
  * @param   pszDesc         Description of this handler.  If NULL, the type
  *                          description will be used instead.
+ * @param   ppPhysHandler   Where to return the access handler structure on
+ *                          success.
  */
-VMMDECL(int) PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType,
-                                        RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC, R3PTRTYPE(const char *) pszDesc)
+int pgmHandlerPhysicalExCreate(PVM pVM, PGMPHYSHANDLERTYPE hType, RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC,
+                               R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler)
 {
     PPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLERTYPEINT_FROM_HANDLE(pVM, hType);
-    Log(("PGMHandlerPhysicalRegister: GCPhys=%RGp GCPhysLast=%RGp pvUserR3=%RHv pvUserR0=%RHv pvUserGC=%RRv hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
-         GCPhys, GCPhysLast, pvUserR3, pvUserR0, pvUserRC, hType, pType->enmKind, R3STRING(pType->pszDesc), pszDesc, R3STRING(pszDesc)));
+    Log(("pgmHandlerPhysicalExCreate: pvUserR3=%RHv pvUserR0=%RHv pvUserGC=%RRv hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
+         pvUserR3, pvUserR0, pvUserRC, hType, pType->enmKind, R3STRING(pType->pszDesc), pszDesc, R3STRING(pszDesc)));
 
     /*
      * Validate input.
      */
+    AssertPtr(ppPhysHandler);
     AssertReturn(pType->u32Magic == PGMPHYSHANDLERTYPEINT_MAGIC, VERR_INVALID_HANDLE);
+    AssertMsgReturn(    (RTRCUINTPTR)pvUserRC < 0x10000
+                    ||  MMHyperR3ToRC(pVM, MMHyperRCToR3(pVM, pvUserRC)) == pvUserRC,
+                    ("Not RC pointer! pvUserRC=%RRv\n", pvUserRC),
+                    VERR_INVALID_PARAMETER);
+    AssertMsgReturn(    (RTR0UINTPTR)pvUserR0 < 0x10000
+                    ||  MMHyperR3ToR0(pVM, MMHyperR0ToR3(pVM, pvUserR0)) == pvUserR0,
+                    ("Not R0 pointer! pvUserR0=%RHv\n", pvUserR0),
+                    VERR_INVALID_PARAMETER);
+
+    /*
+     * Allocate and initialize the new entry.
+     */
+    PPGMPHYSHANDLER pNew;
+    int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
+    if (RT_SUCCESS(rc))
+    {
+        pNew->Core.Key      = NIL_RTGCPHYS;
+        pNew->Core.KeyLast  = NIL_RTGCPHYS;
+        pNew->cPages        = 0;
+        pNew->cAliasedPages = 0;
+        pNew->cTmpOffPages  = 0;
+        pNew->pvUserR3      = pvUserR3;
+        pNew->pvUserR0      = pvUserR0;
+        pNew->pvUserRC      = pvUserRC;
+        pNew->hType         = hType;
+        pNew->pszDesc       = pszDesc != NIL_RTR3PTR ? pszDesc : pType->pszDesc;
+        pgmHandlerPhysicalTypeRetain(pVM, pType);
+        *ppPhysHandler = pNew;
+        return VINF_SUCCESS;
+    }
+
+    return rc;
+}
+
+
+/**
+ * Duplicates a physical access handler.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS when successfully installed.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pPhysHandlerSrc The source handler to duplicate
+ * @param   ppPhysHandler   Where to return the access handler structure on
+ *                          success.
+ */
+int pgmHandlerPhysicalExDup(PVM pVM, PPGMPHYSHANDLER pPhysHandlerSrc, PPGMPHYSHANDLER *ppPhysHandler)
+{
+    return pgmHandlerPhysicalExCreate(pVM,
+                                      pPhysHandlerSrc->hType,
+                                      pPhysHandlerSrc->pvUserR3,
+                                      pPhysHandlerSrc->pvUserR0,
+                                      pPhysHandlerSrc->pvUserRC,
+                                      pPhysHandlerSrc->pszDesc,
+                                      ppPhysHandler);
+}
+
+
+/**
+ * Register a access handler for a physical range.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS when successfully installed.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pPhysHandler    The physical handler.
+ * @param   GCPhys          Start physical address.
+ * @param   GCPhysLast      Last physical address. (inclusive)
+ */
+int pgmHandlerPhysicalExRegister(PVM pVM, PPGMPHYSHANDLER pPhysHandler, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
+{
+    /*
+     * Validate input.
+     */
+    AssertPtr(pPhysHandler);
+    PPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLERTYPEINT_FROM_HANDLE(pVM, pPhysHandler->hType);
+    Assert(pType->u32Magic == PGMPHYSHANDLERTYPEINT_MAGIC);
+    Log(("pgmHandlerPhysicalExRegister: GCPhys=%RGp GCPhysLast=%RGp hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
+         GCPhys, GCPhysLast, pPhysHandler->hType, pType->enmKind, R3STRING(pType->pszDesc), pPhysHandler->pszDesc, R3STRING(pPhysHandler->pszDesc)));
+    AssertReturn(pPhysHandler->Core.Key == NIL_RTGCPHYS, VERR_WRONG_ORDER);
+
     AssertMsgReturn(GCPhys < GCPhysLast, ("GCPhys >= GCPhysLast (%#x >= %#x)\n", GCPhys, GCPhysLast), VERR_INVALID_PARAMETER);
     switch (pType->enmKind)
     {
@@ -172,14 +253,6 @@ VMMDECL(int) PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhy
             AssertMsgFailed(("Invalid input enmKind=%d!\n", pType->enmKind));
             return VERR_INVALID_PARAMETER;
     }
-    AssertMsgReturn(    (RTRCUINTPTR)pvUserRC < 0x10000
-                    ||  MMHyperR3ToRC(pVM, MMHyperRCToR3(pVM, pvUserRC)) == pvUserRC,
-                    ("Not RC pointer! pvUserRC=%RRv\n", pvUserRC),
-                    VERR_INVALID_PARAMETER);
-    AssertMsgReturn(    (RTR0UINTPTR)pvUserR0 < 0x10000
-                    ||  MMHyperR3ToR0(pVM, MMHyperR0ToR3(pVM, pvUserR0)) == pvUserR0,
-                    ("Not R0 pointer! pvUserR0=%RHv\n", pvUserR0),
-                    VERR_INVALID_PARAMETER);
 
     /*
      * We require the range to be within registered ram.
@@ -187,8 +260,7 @@ VMMDECL(int) PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhy
      */
     PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
     if (   !pRam
-        || GCPhysLast < pRam->GCPhys
-        || GCPhys > pRam->GCPhysLast)
+        || GCPhysLast > pRam->GCPhysLast)
     {
 #ifdef IN_RING3
         DBGFR3Info(pVM->pUVM, "phys", NULL, NULL);
@@ -196,38 +268,24 @@ VMMDECL(int) PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhy
         AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
         return VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE;
     }
+    Assert(GCPhys >= pRam->GCPhys && GCPhys < pRam->GCPhysLast);
+    Assert(GCPhysLast <= pRam->GCPhysLast && GCPhysLast >= pRam->GCPhys);
 
     /*
-     * Allocate and initialize the new entry.
+     * Try insert into list.
      */
-    PPGMPHYSHANDLER pNew;
-    int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    pNew->Core.Key      = GCPhys;
-    pNew->Core.KeyLast  = GCPhysLast;
-    pNew->cPages        = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
-    pNew->cAliasedPages = 0;
-    pNew->cTmpOffPages  = 0;
-    pNew->pvUserR3      = pvUserR3;
-    pNew->pvUserR0      = pvUserR0;
-    pNew->pvUserRC      = pvUserRC;
-    pNew->hType         = hType;
-    pNew->pszDesc       = pszDesc != NIL_RTR3PTR ? pszDesc : pType->pszDesc;
-    pgmHandlerPhysicalTypeRetain(pVM, pType);
+    pPhysHandler->Core.Key     = GCPhys;
+    pPhysHandler->Core.KeyLast = GCPhysLast;
+    pPhysHandler->cPages       = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
 
     pgmLock(pVM);
-
-    /*
-     * Try insert into list.
-     */
-    if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pNew->Core))
+    if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pPhysHandler->Core))
     {
-        rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pNew, pRam);
+        int rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pPhysHandler, pRam);
         if (rc == VINF_PGM_SYNC_CR3)
             rc = VINF_PGM_GCPHYS_ALIASED;
         pgmUnlock(pVM);
+
 #ifdef VBOX_WITH_REM
 # ifndef IN_RING3
         REMNotifyHandlerPhysicalRegister(pVM, pType->enmKind, GCPhys, GCPhysLast - GCPhys + 1, !!pType->pfnHandlerR3);
@@ -239,21 +297,66 @@ VMMDECL(int) PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhy
             Log(("PGMHandlerPhysicalRegisterEx: returns %Rrc (%RGp-%RGp)\n", rc, GCPhys, GCPhysLast));
         return rc;
     }
-
     pgmUnlock(pVM);
 
+    pPhysHandler->Core.Key     = NIL_RTGCPHYS;
+    pPhysHandler->Core.KeyLast = NIL_RTGCPHYS;
+
 #if defined(IN_RING3) && defined(VBOX_STRICT)
     DBGFR3Info(pVM->pUVM, "handlers", "phys nostats", NULL);
 #endif
     AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp pszDesc=%s/%s\n",
-                     GCPhys, GCPhysLast, R3STRING(pszDesc), R3STRING(pType->pszDesc)));
-    pgmHandlerPhysicalTypeRelease(pVM, pType);
-    MMHyperFree(pVM, pNew);
+                     GCPhys, GCPhysLast, R3STRING(pPhysHandler->pszDesc), R3STRING(pType->pszDesc)));
     return VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
 }
 
 
 /**
+ * Register a access handler for a physical range.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS when successfully installed.
+ * @retval  VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
+ *          the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
+ *          flagged together with a pool clearing.
+ * @retval  VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
+ *          one. A debug assertion is raised.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   GCPhys          Start physical address.
+ * @param   GCPhysLast      Last physical address. (inclusive)
+ * @param   hType           The handler type registration handle.
+ * @param   pvUserR3        User argument to the R3 handler.
+ * @param   pvUserR0        User argument to the R0 handler.
+ * @param   pvUserRC        User argument to the RC handler. This can be a value
+ *                          less that 0x10000 or a (non-null) pointer that is
+ *                          automatically relocated.
+ * @param   pszDesc         Description of this handler.  If NULL, the type
+ *                          description will be used instead.
+ */
+VMMDECL(int) PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType,
+                                        RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC, R3PTRTYPE(const char *) pszDesc)
+{
+#ifdef LOG_ENABLED
+    PPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLERTYPEINT_FROM_HANDLE(pVM, hType);
+    Log(("PGMHandlerPhysicalRegister: GCPhys=%RGp GCPhysLast=%RGp pvUserR3=%RHv pvUserR0=%RHv pvUserGC=%RRv hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
+         GCPhys, GCPhysLast, pvUserR3, pvUserR0, pvUserRC, hType, pType->enmKind, R3STRING(pType->pszDesc), pszDesc, R3STRING(pszDesc)));
+#endif
+
+    PPGMPHYSHANDLER pNew;
+    int rc = pgmHandlerPhysicalExCreate(pVM, hType, pvUserR3, pvUserR0, pvUserRC, pszDesc, &pNew);
+    if (RT_SUCCESS(rc))
+    {
+        rc = pgmHandlerPhysicalExRegister(pVM, pNew, GCPhys, GCPhysLast);
+        if (RT_SUCCESS(rc))
+            return rc;
+        pgmHandlerPhysicalExDestroy(pVM, pNew);
+    }
+    return rc;
+}
+
+
+/**
  * Sets ram range flags and attempts updating shadow PTs.
  *
  * @returns VBox status code.
@@ -312,7 +415,88 @@ static int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDL
 
 
 /**
- * Register a physical page access handler.
+ * Deregister a physical page access handler.
+ *
+ * @returns VBox status code.
+ * @param   pVM             The cross context VM structure.
+ * @param   pPhysHandler    The handler to deregister (but not free).
+ */
+int pgmHandlerPhysicalExDeregister(PVM pVM, PPGMPHYSHANDLER pPhysHandler)
+{
+    LogFlow(("pgmHandlerPhysicalExDeregister: Removing Range %RGp-%RGp %s\n",
+             pPhysHandler->Core.Key, pPhysHandler->Core.KeyLast, R3STRING(pPhysHandler->pszDesc)));
+    AssertReturn(pPhysHandler->Core.Key != NIL_RTGCPHYS, VERR_PGM_HANDLER_NOT_FOUND);
+
+    /*
+     * Remove the handler from the tree.
+     */
+    pgmLock(pVM);
+    PPGMPHYSHANDLER pRemoved = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers,
+                                                                    pPhysHandler->Core.Key);
+    if (pRemoved == pPhysHandler)
+    {
+        /*
+         * Clear the page bits, notify the REM about this change and clear
+         * the cache.
+         */
+        pgmHandlerPhysicalResetRamFlags(pVM, pPhysHandler);
+        pgmHandlerPhysicalDeregisterNotifyREM(pVM, pPhysHandler);
+        pVM->pgm.s.pLastPhysHandlerR0 = 0;
+        pVM->pgm.s.pLastPhysHandlerR3 = 0;
+        pVM->pgm.s.pLastPhysHandlerRC = 0;
+
+        pPhysHandler->Core.Key     = NIL_RTGCPHYS;
+        pPhysHandler->Core.KeyLast = NIL_RTGCPHYS;
+
+        pgmUnlock(pVM);
+
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * Both of the failure conditions here are considered internal processing
+     * errors because they can only be caused by race conditions or corruption.
+     * If we ever need to handle concurrent deregistration, we have to move
+     * the NIL_RTGCPHYS check inside the PGM lock.
+     */
+    if (pRemoved)
+        RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pRemoved->Core);
+
+    pgmUnlock(pVM);
+
+    if (!pRemoved)
+        AssertMsgFailed(("Didn't find range starting at %RGp in the tree!\n", pPhysHandler->Core.Key));
+    else
+        AssertMsgFailed(("Found different handle at %RGp in the tree: got %p insteaded of %p\n",
+                         pPhysHandler->Core.Key, pRemoved, pPhysHandler));
+    return VERR_PGM_HANDLER_IPE_1;
+}
+
+
+/**
+ * Destroys (frees) a physical handler.
+ *
+ * The caller must deregister it before destroying it!
+ *
+ * @returns VBox status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   pHandler    The handler to free.  NULL if ignored.
+ */
+int pgmHandlerPhysicalExDestroy(PVM pVM, PPGMPHYSHANDLER pHandler)
+{
+    if (pHandler)
+    {
+        AssertPtr(pHandler);
+        AssertReturn(pHandler->Core.Key == NIL_RTGCPHYS, VERR_WRONG_ORDER);
+        PGMHandlerPhysicalTypeRelease(pVM, pHandler->hType);
+        MMHyperFree(pVM, pHandler);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Deregister a physical page access handler.
  *
  * @returns VBox status code.
  * @param   pVM         The cross context VM structure.
@@ -324,25 +508,29 @@ VMMDECL(int)  PGMHandlerPhysicalDeregister(PVM pVM, RTGCPHYS GCPhys)
      * Find the handler.
      */
     pgmLock(pVM);
-    PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
-    if (pCur)
+    PPGMPHYSHANDLER pRemoved = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
+    if (pRemoved)
     {
-        LogFlow(("PGMHandlerPhysicalDeregister: Removing Range %RGp-%RGp %s\n", pCur->Core.Key, pCur->Core.KeyLast, R3STRING(pCur->pszDesc)));
+        LogFlow(("PGMHandlerPhysicalDeregister: Removing Range %RGp-%RGp %s\n",
+                 pRemoved->Core.Key, pRemoved->Core.KeyLast, R3STRING(pRemoved->pszDesc)));
 
         /*
          * Clear the page bits, notify the REM about this change and clear
          * the cache.
          */
-        pgmHandlerPhysicalResetRamFlags(pVM, pCur);
-        pgmHandlerPhysicalDeregisterNotifyREM(pVM, pCur);
+        pgmHandlerPhysicalResetRamFlags(pVM, pRemoved);
+        pgmHandlerPhysicalDeregisterNotifyREM(pVM, pRemoved);
         pVM->pgm.s.pLastPhysHandlerR0 = 0;
         pVM->pgm.s.pLastPhysHandlerR3 = 0;
         pVM->pgm.s.pLastPhysHandlerRC = 0;
-        PGMHandlerPhysicalTypeRelease(pVM, pCur->hType);
-        MMHyperFree(pVM, pCur);
+
         pgmUnlock(pVM);
+
+        pRemoved->Core.Key = NIL_RTGCPHYS;
+        pgmHandlerPhysicalExDestroy(pVM, pRemoved);
         return VINF_SUCCESS;
     }
+
     pgmUnlock(pVM);
 
     AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
diff --git a/src/VBox/VMM/VMMAll/PGMAllPhys.cpp b/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
index 60f9914..73e023c 100644
--- a/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
+++ b/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
@@ -1228,7 +1228,7 @@ static int pgmPhysPageMapCommon(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMP
                                RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)), PGM_PAGE_GET_TYPE(pPage), GCPhys,
                                pPage->s.idPage, pPage->s.uStateY),
                               VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
-        PPGMMMIO2RANGE pMmio2Range = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[idMmio2 - 1];
+        PPGMREGMMIORANGE pMmio2Range = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[idMmio2 - 1];
         AssertLogRelReturn(pMmio2Range, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
         AssertLogRelReturn(pMmio2Range->idMmio2 == idMmio2, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
         AssertLogRelReturn(iPage < (pMmio2Range->RamRange.cb >> PAGE_SHIFT), VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
diff --git a/src/VBox/VMM/VMMR0/HMVMXR0.cpp b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
index dbd520a..e65f39d 100644
--- a/src/VBox/VMM/VMMR0/HMVMXR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
@@ -9015,7 +9015,7 @@ static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pC
 
         /* Restore any residual host-state and save any bits shared between host
            and guest into the guest-CPU state.  Re-enables interrupts! */
-        hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, VBOXSTRICTRC_TODO(rcStrict));
+        hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rcRun);
 
         /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
         if (RT_SUCCESS(rcRun))
@@ -10149,7 +10149,7 @@ static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCt
          * Restore any residual host-state and save any bits shared between host
          * and guest into the guest-CPU state.  Re-enables interrupts!
          */
-        hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, VBOXSTRICTRC_TODO(rcStrict));
+        hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rcRun);
 
         /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
         if (RT_SUCCESS(rcRun))
diff --git a/src/VBox/VMM/VMMR0/PDMR0Device.cpp b/src/VBox/VMM/VMMR0/PDMR0Device.cpp
index 1d0a882..2a4f325 100644
--- a/src/VBox/VMM/VMMR0/PDMR0Device.cpp
+++ b/src/VBox/VMM/VMMR0/PDMR0Device.cpp
@@ -20,6 +20,7 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_PDM_DEVICE
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
 #include "PDMInternal.h"
 #include <VBox/vmm/pdm.h>
 #include <VBox/vmm/pgm.h>
@@ -67,18 +68,21 @@ static bool pdmR0IsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc);
  */
 
 /** @interface_method_impl{PDMDEVHLPR0,pfnPCIPhysRead} */
-static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                                 void *pvBuf, size_t cbRead)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
 
 #ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
     /*
      * Just check the busmaster setting here and forward the request to the generic read helper.
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR0;
-    AssertReleaseMsg(pPciDev, ("No PCI device registered!\n"));
-
-    if (!PCIDevIsBusmaster(pPciDev))
+    if (PCIDevIsBusmaster(pPciDev))
+    { /* likely */ }
+    else
     {
         Log(("pdmRCDevHlp_PCIPhysRead: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbRead=%#zx\n",
              pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbRead));
@@ -91,18 +95,21 @@ static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GC
 
 
 /** @interface_method_impl{PDMDEVHLPR0,pfnPCIPhysWrite} */
-static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                                  const void *pvBuf, size_t cbWrite)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
 
 #ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
     /*
      * Just check the busmaster setting here and forward the request to the generic read helper.
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR0;
-    AssertReleaseMsg(pPciDev, ("No PCI device registered!\n"));
-
-    if (!PCIDevIsBusmaster(pPciDev))
+    if (PCIDevIsBusmaster(pPciDev))
+    { /* likely */ }
+    else
     {
         Log(("pdmRCDevHlp_PCIPhysWrite: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbWrite=%#zx\n",
              pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbWrite));
@@ -115,13 +122,16 @@ static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS G
 
 
 /** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */
-static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
+static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
-    LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel));
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
+    AssertReturnVoid(pPciDev);
+    LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: pPciDev=%p:{%#x} iIrq=%d iLevel=%d\n",
+             pDevIns, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iIrq, iLevel));
     PVM          pVM     = pDevIns->Internal.s.pVMR0;
-    PPCIDEVICE   pPciDev = pDevIns->Internal.s.pPciDeviceR0;
-    PPDMPCIBUS   pPciBus = pDevIns->Internal.s.pPciBusR0;
+    PPDMPCIBUS   pPciBus = pPciDev->Int.s.pPdmBusR0;
 
     pdmLock(pVM);
     uint32_t uTagSrc;
@@ -136,8 +146,7 @@ static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, in
     else
         uTagSrc = pDevIns->Internal.s.uLastIrqTag;
 
-    if (    pPciDev
-        &&  pPciBus
+    if (    pPciBus
         &&  pPciBus->pDevInsR0)
     {
         pPciBus->pfnSetIrqR0(pPciBus->pDevInsR0, pPciDev, iIrq, iLevel, uTagSrc);
@@ -157,9 +166,10 @@ static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, in
 
         pTask->enmOp = PDMDEVHLPTASKOP_PCI_SET_IRQ;
         pTask->pDevInsR3 = PDMDEVINS_2_R3PTR(pDevIns);
-        pTask->u.SetIRQ.iIrq = iIrq;
-        pTask->u.SetIRQ.iLevel = iLevel;
-        pTask->u.SetIRQ.uTagSrc = uTagSrc;
+        pTask->u.PciSetIRQ.iIrq = iIrq;
+        pTask->u.PciSetIRQ.iLevel = iLevel;
+        pTask->u.PciSetIRQ.uTagSrc = uTagSrc;
+        pTask->u.PciSetIRQ.pPciDevR3 = MMHyperR0ToR3(pVM, pPciDev);
 
         PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     }
@@ -168,7 +178,7 @@ static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, in
 }
 
 
-/** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */
+/** @interface_method_impl{PDMDEVHLPR0,pfnISASetIrq} */
 static DECLCALLBACK(void) pdmR0DevHlp_ISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
@@ -409,6 +419,16 @@ extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp =
     pdmR0DevHlp_TMTimeVirtGetFreq,
     pdmR0DevHlp_TMTimeVirtGetNano,
     pdmR0DevHlp_DBGFTraceBuf,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
     PDM_DEVHLPR0_VERSION
 };
 
@@ -786,9 +806,9 @@ static DECLCALLBACK(void) pdmR0PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq,
         {
             pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ;
             pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
-            pTask->u.SetIRQ.iIrq = iIrq;
-            pTask->u.SetIRQ.iLevel = iLevel;
-            pTask->u.SetIRQ.uTagSrc = uTagSrc;
+            pTask->u.IoApicSetIRQ.iIrq = iIrq;
+            pTask->u.IoApicSetIRQ.iLevel = iLevel;
+            pTask->u.IoApicSetIRQ.uTagSrc = uTagSrc;
 
             PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
         }
@@ -1022,9 +1042,9 @@ static bool pdmR0IsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc)
 
     pTask->enmOp = PDMDEVHLPTASKOP_ISA_SET_IRQ;
     pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
-    pTask->u.SetIRQ.iIrq = iIrq;
-    pTask->u.SetIRQ.iLevel = iLevel;
-    pTask->u.SetIRQ.uTagSrc = uTagSrc;
+    pTask->u.IsaSetIRQ.iIrq = iIrq;
+    pTask->u.IsaSetIRQ.iLevel = iLevel;
+    pTask->u.IsaSetIRQ.uTagSrc = uTagSrc;
 
     PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
     return false;
diff --git a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
index 3d1f45e..789dbef 100644
--- a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
+++ b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
@@ -674,7 +674,7 @@ static PCPUMCPUIDLEAF cpumR3CpuIdEnsureSpace(PVM pVM, PCPUMCPUIDLEAF *ppaLeaves,
  *
  * @returns VINF_SUCCESS or VERR_NO_MEMORY.  On error, *ppaLeaves is freed, so
  *          the caller need do no more work.
- * @param   ppaLeaves       Pointer to the the pointer to the array of sorted
+ * @param   ppaLeaves       Pointer to the pointer to the array of sorted
  *                          CPUID leaves and sub-leaves.
  * @param   pcLeaves        Where we keep the leaf count for *ppaLeaves.
  * @param   uLeaf           The leaf we're adding.
@@ -755,7 +755,7 @@ static void cpumR3CpuIdAssertOrder(PCPUMCPUIDLEAF paLeaves, uint32_t cLeaves)
  * @returns VBox status code.
  * @param   pVM         The cross context VM structure.  If NULL, use
  *                      the process heap, otherwise the VM's hyper heap.
- * @param   ppaLeaves   Pointer to the the pointer to the array of sorted
+ * @param   ppaLeaves   Pointer to the pointer to the array of sorted
  *                      CPUID leaves and sub-leaves. Must be NULL if using
  *                      the hyper heap.
  * @param   pcLeaves    Where we keep the leaf count for *ppaLeaves. Must
diff --git a/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp b/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp
index e5e2856..6c9e778 100644
--- a/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp
+++ b/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp
@@ -320,7 +320,7 @@ void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta)
 {
     /*
      * We will relocate the raw-mode context modules by offDelta if they have
-     * been injected into the the DBGF_AS_RC map.
+     * been injected into the DBGF_AS_RC map.
      */
     if (   pUVM->dbgf.s.afAsAliasPopuplated[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)]
         && offDelta != 0)
diff --git a/src/VBox/VMM/VMMR3/DBGFBp.cpp b/src/VBox/VMM/VMMR3/DBGFBp.cpp
index 51d8052..7ae3974 100644
--- a/src/VBox/VMM/VMMR3/DBGFBp.cpp
+++ b/src/VBox/VMM/VMMR3/DBGFBp.cpp
@@ -923,7 +923,7 @@ VMMR3DECL(int)  DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, ui
  * @returns VBox status code.
  * @param   pUVM            The user mode VM handle.
  * @param   pGCPhys         The start of the MMIO range to break on.
- * @param   cb              The the size of the MMIO range.
+ * @param   cb              The size of the MMIO range.
  * @param   fAccess         The access we want to break on.
  * @param   piHitTrigger    The hit count at which the breakpoint start triggering.
  *                          Use 0 (or 1) if it's gonna trigger at once.
diff --git a/src/VBox/VMM/VMMR3/GIM.cpp b/src/VBox/VMM/VMMR3/GIM.cpp
index 8c4aefe..39eed74 100644
--- a/src/VBox/VMM/VMMR3/GIM.cpp
+++ b/src/VBox/VMM/VMMR3/GIM.cpp
@@ -611,7 +611,7 @@ VMMR3_INT_DECL(int) GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCP
     /*
      * Map the MMIO2 region over the specified guest-physical address.
      */
-    int rc = PDMDevHlpMMIO2Map(pDevIns, pRegion->iRegion, GCPhysRegion);
+    int rc = PDMDevHlpMMIOExMap(pDevIns, NULL, pRegion->iRegion, GCPhysRegion);
     if (RT_SUCCESS(rc))
     {
         /*
diff --git a/src/VBox/VMM/VMMR3/IOM.cpp b/src/VBox/VMM/VMMR3/IOM.cpp
index 2f06161..8da2386 100644
--- a/src/VBox/VMM/VMMR3/IOM.cpp
+++ b/src/VBox/VMM/VMMR3/IOM.cpp
@@ -1653,6 +1653,219 @@ VMMR3_INT_DECL(int) IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GC
 
 
 /**
+ * Pre-Registers a MMIO region.
+ *
+ * The rest of of the manipulation of this region goes thru the PGMPhysMMIOEx*
+ * APIs: PGMR3PhysMMIOExMap, PGMR3PhysMMIOExUnmap, PGMR3PhysMMIOExDeregister
+ *
+ * @returns VBox status code.
+ * @param   pVM                 Pointer to the cross context VM structure.
+ * @param   pDevIns             The device.
+ * @param   iSubDev             The sub-device number.
+ * @param   iRegion             The region number.
+ * @param   cbRegion            The size of the MMIO region.  Must be a multiple
+ *                              of X86_PAGE_SIZE
+ * @param   fFlags              Flags, see IOMMMIO_FLAGS_XXX.
+ * @param   pszDesc             Pointer to description string. This must not be
+ *                              freed.
+ * @param   pvUserR3            Ring-3 user pointer.
+ * @param   pfnWriteCallbackR3  Callback for handling writes, ring-3. Mandatory.
+ * @param   pfnReadCallbackR3   Callback for handling reads, ring-3. Mandatory.
+ * @param   pfnFillCallbackR3   Callback for handling fills, ring-3. Optional.
+ * @param   pvUserR0            Ring-0 user pointer.
+ * @param   pfnWriteCallbackR0  Callback for handling writes, ring-0. Optional.
+ * @param   pfnReadCallbackR0   Callback for handling reads, ring-0. Optional.
+ * @param   pfnFillCallbackR0   Callback for handling fills, ring-0. Optional.
+ * @param   pvUserRC            Raw-mode context user pointer.  This will be
+ *                              relocated with the hypervisor guest mapping if
+ *                              the unsigned integer value is 0x10000 or above.
+ * @param   pfnWriteCallbackRC  Callback for handling writes, RC. Optional.
+ * @param   pfnReadCallbackRC   Callback for handling reads, RC. Optional.
+ * @param   pfnFillCallbackRC   Callback for handling fills, RC. Optional.
+ */
+VMMR3_INT_DECL(int)  IOMR3MmioExPreRegister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRegion,
+                                            uint32_t fFlags, const char *pszDesc,
+                                            RTR3PTR pvUserR3,
+                                            R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR3,
+                                            R3PTRTYPE(PFNIOMMMIOREAD)  pfnReadCallbackR3,
+                                            R3PTRTYPE(PFNIOMMMIOFILL)  pfnFillCallbackR3,
+                                            RTR0PTR pvUserR0,
+                                            R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR0,
+                                            R0PTRTYPE(PFNIOMMMIOREAD)  pfnReadCallbackR0,
+                                            R0PTRTYPE(PFNIOMMMIOFILL)  pfnFillCallbackR0,
+                                            RTRCPTR pvUserRC,
+                                            RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackRC,
+                                            RCPTRTYPE(PFNIOMMMIOREAD)  pfnReadCallbackRC,
+                                            RCPTRTYPE(PFNIOMMMIOFILL)  pfnFillCallbackRC)
+{
+    LogFlow(("IOMR3MmioExPreRegister: pDevIns=%p iSubDev=%u iRegion=%u cbRegion=%RGp fFlags=%#x pszDesc=%s\n"
+             "                        pvUserR3=%RHv pfnWriteCallbackR3=%RHv pfnReadCallbackR3=%RHv pfnFillCallbackR3=%RHv\n"
+             "                        pvUserR0=%RHv pfnWriteCallbackR0=%RHv pfnReadCallbackR0=%RHv pfnFillCallbackR0=%RHv\n"
+             "                        pvUserRC=%RRv pfnWriteCallbackRC=%RRv pfnReadCallbackRC=%RRv pfnFillCallbackRC=%RRv\n",
+             pDevIns, iSubDev, iRegion, cbRegion, fFlags, pszDesc,
+             pvUserR3, pfnWriteCallbackR3, pfnReadCallbackR3, pfnFillCallbackR3,
+             pvUserR0, pfnWriteCallbackR0, pfnReadCallbackR0, pfnFillCallbackR0,
+             pvUserRC, pfnWriteCallbackRC, pfnReadCallbackRC, pfnFillCallbackRC));
+
+    /*
+     * Validate input.
+     */
+    AssertReturn(cbRegion > 0,  VERR_INVALID_PARAMETER);
+    AssertReturn(RT_ALIGN_T(cbRegion, X86_PAGE_SIZE, RTGCPHYS), VERR_INVALID_PARAMETER);
+    AssertMsgReturn(   !(fFlags & ~IOMMMIO_FLAGS_VALID_MASK)
+                    && (fFlags & IOMMMIO_FLAGS_READ_MODE)  <= IOMMMIO_FLAGS_READ_DWORD_QWORD
+                    && (fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
+                    ("%#x\n", fFlags),
+                    VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pfnWriteCallbackR3, VERR_INVALID_POINTER);
+    AssertPtrReturn(pfnReadCallbackR3, VERR_INVALID_POINTER);
+
+    /*
+     * Allocate new range record and initialize it.
+     */
+    PIOMMMIORANGE pRange;
+    int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
+    if (RT_SUCCESS(rc))
+    {
+        pRange->Core.Key            = NIL_RTGCPHYS;
+        pRange->Core.KeyLast        = NIL_RTGCPHYS;
+        pRange->GCPhys              = NIL_RTGCPHYS;
+        pRange->cb                  = cbRegion;
+        pRange->cRefs               = 1; /* The PGM reference. */
+        pRange->fFlags              = fFlags;
+
+        pRange->pvUserR3            = pvUserR3;
+        pRange->pDevInsR3           = pDevIns;
+        pRange->pfnReadCallbackR3   = pfnReadCallbackR3;
+        pRange->pfnWriteCallbackR3  = pfnWriteCallbackR3;
+        pRange->pfnFillCallbackR3   = pfnFillCallbackR3;
+        pRange->pszDesc             = pszDesc;
+
+        if (pfnReadCallbackR0 || pfnWriteCallbackR0 || pfnFillCallbackR0)
+        {
+            pRange->pvUserR0            = pvUserR0;
+            pRange->pDevInsR0           = MMHyperCCToR0(pVM, pDevIns);
+            pRange->pfnReadCallbackR0   = pfnReadCallbackR0;
+            pRange->pfnWriteCallbackR0  = pfnWriteCallbackR0;
+            pRange->pfnFillCallbackR0   = pfnFillCallbackR0;
+        }
+
+        if (pfnReadCallbackRC || pfnWriteCallbackRC || pfnFillCallbackRC)
+        {
+            pRange->pvUserRC            = pvUserRC;
+            pRange->pDevInsRC           = MMHyperCCToRC(pVM, pDevIns);
+            pRange->pfnReadCallbackRC   = pfnReadCallbackRC;
+            pRange->pfnWriteCallbackRC  = pfnWriteCallbackRC;
+            pRange->pfnFillCallbackRC   = pfnFillCallbackRC;
+        }
+
+        /*
+         * Try register it with PGM.  PGM will call us back when it's mapped in
+         * and out of the guest address space, and once it's destroyed.
+         */
+        rc = PGMR3PhysMMIOExPreRegister(pVM, pDevIns, iSubDev, iRegion, cbRegion, pVM->iom.s.hMmioHandlerType,
+                                        pRange, MMHyperR3ToR0(pVM, pRange), MMHyperR3ToRC(pVM, pRange), pszDesc);
+        if (RT_SUCCESS(rc))
+            return VINF_SUCCESS;
+
+        MMHyperFree(pVM, pRange);
+    }
+    if (pDevIns->iInstance > 0)
+        MMR3HeapFree((void *)pszDesc);
+    return rc;
+
+}
+
+
+/**
+ * Notfication from PGM that the pre-registered MMIO region has been mapped into
+ * user address space.
+ *
+ * @returns VBox status code.
+ * @param   pVM             Pointer to the cross context VM structure.
+ * @param   pvUser          The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.
+ * @param   GCPhys          The mapping address.
+ * @remarks Called while owning the PGM lock.
+ */
+VMMR3_INT_DECL(int) IOMR3MmioExNotifyMapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys)
+{
+    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
+    AssertReturn(pRange->GCPhys == NIL_RTGCPHYS, VERR_IOM_MMIO_IPE_1);
+
+    IOM_LOCK_EXCL(pVM);
+    Assert(pRange->GCPhys == NIL_RTGCPHYS);
+    pRange->GCPhys       = GCPhys;
+    pRange->Core.Key     = GCPhys;
+    pRange->Core.KeyLast = GCPhys + pRange->cb - 1;
+    if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))
+    {
+        iomR3FlushCache(pVM);
+        IOM_UNLOCK_EXCL(pVM);
+        return VINF_SUCCESS;
+    }
+    IOM_UNLOCK_EXCL(pVM);
+
+    AssertLogRelMsgFailed(("RTAvlroGCPhysInsert failed on %RGp..%RGp - %s\n", pRange->Core.Key, pRange->Core.KeyLast, pRange->pszDesc));
+    pRange->GCPhys       = NIL_RTGCPHYS;
+    pRange->Core.Key     = NIL_RTGCPHYS;
+    pRange->Core.KeyLast = NIL_RTGCPHYS;
+    return VERR_IOM_MMIO_IPE_2;
+}
+
+
+/**
+ * Notfication from PGM that the pre-registered MMIO region has been unmapped
+ * from user address space.
+ *
+ * @param   pVM             Pointer to the cross context VM structure.
+ * @param   pvUser          The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.
+ * @param   GCPhys          The mapping address.
+ * @remarks Called while owning the PGM lock.
+ */
+VMMR3_INT_DECL(void) IOMR3MmioExNotifyUnmapped(PVM pVM, void *pvUser, RTGCPHYS GCPhys)
+{
+    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
+    AssertLogRelReturnVoid(pRange->GCPhys == GCPhys);
+
+    IOM_LOCK_EXCL(pVM);
+    Assert(pRange->GCPhys == GCPhys);
+    PIOMMMIORANGE pRemoved = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesR3->MMIOTree, GCPhys);
+    if (pRemoved == pRange)
+    {
+        pRange->GCPhys       = NIL_RTGCPHYS;
+        pRange->Core.Key     = NIL_RTGCPHYS;
+        pRange->Core.KeyLast = NIL_RTGCPHYS;
+        iomR3FlushCache(pVM);
+        IOM_UNLOCK_EXCL(pVM);
+    }
+    else
+    {
+        if (pRemoved)
+            RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRemoved->Core);
+        IOM_UNLOCK_EXCL(pVM);
+        AssertLogRelMsgFailed(("RTAvlroGCPhysRemove returned %p instead of %p for %RGp (%s)\n",
+                               pRemoved, pRange, GCPhys, pRange->pszDesc));
+    }
+}
+
+
+/**
+ * Notfication from PGM that the pre-registered MMIO region has been mapped into
+ * user address space.
+ *
+ * @param   pVM             Pointer to the cross context VM structure.
+ * @param   pvUser          The pvUserR3 argument of PGMR3PhysMMIOExPreRegister.
+ * @remarks Called while owning the PGM lock.
+ */
+VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser)
+{
+    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
+    AssertLogRelReturnVoid(pRange->GCPhys == NIL_RTGCPHYS);
+    iomMmioReleaseRange(pVM, pRange);
+}
+
+
+/**
  * Handles the unlikely and probably fatal merge cases.
  *
  * @returns Merged status code.
diff --git a/src/VBox/VMM/VMMR3/MMHyper.cpp b/src/VBox/VMM/VMMR3/MMHyper.cpp
index 8c9bfb0..81450a9 100644
--- a/src/VBox/VMM/VMMR3/MMHyper.cpp
+++ b/src/VBox/VMM/VMMR3/MMHyper.cpp
@@ -276,7 +276,8 @@ VMMR3DECL(int) MMR3HyperInitFinalize(PVM pVM)
                 for (RTGCPHYS offCur = pLookup->u.MMIO2.off; offCur < offEnd; offCur += PAGE_SIZE)
                 {
                     RTHCPHYS HCPhys;
-                    rc = PGMR3PhysMMIO2GetHCPhys(pVM, pLookup->u.MMIO2.pDevIns, pLookup->u.MMIO2.iRegion, offCur, &HCPhys);
+                    rc = PGMR3PhysMMIO2GetHCPhys(pVM, pLookup->u.MMIO2.pDevIns, pLookup->u.MMIO2.iSubDev,
+                                                 pLookup->u.MMIO2.iRegion, offCur, &HCPhys);
                     if (RT_FAILURE(rc))
                         break;
                     rc = PGMMap(pVM, GCPtr + (offCur - pLookup->u.MMIO2.off), HCPhys, PAGE_SIZE, 0);
@@ -523,24 +524,25 @@ VMMR3DECL(int) MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const cha
  * Maps a portion of an MMIO2 region into the hypervisor region.
  *
  * Callers of this API must never deregister the MMIO2 region before the
- * VM is powered off. If this becomes a requirement MMR3HyperUnmapMMIO2
+ * VM is powered off.  If this becomes a requirement MMR3HyperUnmapMMIO2
  * API will be needed to perform cleanups.
  *
  * @return VBox status code.
  *
  * @param   pVM         The cross context VM structure.
  * @param   pDevIns     The device owning the MMIO2 memory.
+ * @param   iSubDev     The sub-device number.
  * @param   iRegion     The region.
  * @param   off         The offset into the region. Will be rounded down to closest page boundary.
  * @param   cb          The number of bytes to map. Will be rounded up to the closest page boundary.
  * @param   pszDesc     Mapping description.
  * @param   pRCPtr      Where to store the RC address.
  */
-VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
                                 const char *pszDesc, PRTRCPTR pRCPtr)
 {
-    LogFlow(("MMR3HyperMapMMIO2: pDevIns=%p iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pRCPtr=%p\n",
-             pDevIns, iRegion, off, cb, pszDesc, pszDesc, pRCPtr));
+    LogFlow(("MMR3HyperMapMMIO2: pDevIns=%p iSubDev=%#x iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pRCPtr=%p\n",
+             pDevIns, iSubDev, iRegion, off, cb, pszDesc, pszDesc, pRCPtr));
     int rc;
 
     /*
@@ -557,8 +559,8 @@ VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
     for (RTGCPHYS offCur = off; offCur < offEnd; offCur += PAGE_SIZE)
     {
         RTHCPHYS HCPhys;
-        rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iRegion, offCur, &HCPhys);
-        AssertMsgRCReturn(rc, ("rc=%Rrc - iRegion=%d off=%RGp\n", rc, iRegion, off), rc);
+        rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iSubDev, iRegion, offCur, &HCPhys);
+        AssertMsgRCReturn(rc, ("rc=%Rrc - iSubDev=%#x iRegion=%#x off=%RGp\n", rc, iSubDev, iRegion, off), rc);
     }
 
     /*
@@ -571,6 +573,7 @@ VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
     {
         pLookup->enmType = MMLOOKUPHYPERTYPE_MMIO2;
         pLookup->u.MMIO2.pDevIns = pDevIns;
+        pLookup->u.MMIO2.iSubDev = iSubDev;
         pLookup->u.MMIO2.iRegion = iRegion;
         pLookup->u.MMIO2.off = off;
 
@@ -582,7 +585,7 @@ VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
             for (RTGCPHYS offCur = off; offCur < offEnd; offCur += PAGE_SIZE)
             {
                 RTHCPHYS HCPhys;
-                rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iRegion, offCur, &HCPhys);
+                rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iSubDev, iRegion, offCur, &HCPhys);
                 AssertRCReturn(rc, rc);
                 rc = PGMMap(pVM, GCPtr + (offCur - off), HCPhys, PAGE_SIZE, 0);
                 if (RT_FAILURE(rc))
diff --git a/src/VBox/VMM/VMMR3/PDM.cpp b/src/VBox/VMM/VMMR3/PDM.cpp
index 263d63e..95a95b5 100644
--- a/src/VBox/VMM/VMMR3/PDM.cpp
+++ b/src/VBox/VMM/VMMR3/PDM.cpp
@@ -40,22 +40,22 @@
  * Devices register themselves when the module containing them is loaded.  PDM
  * will call the entry point 'VBoxDevicesRegister' when loading a device module.
  * The device module will then use the supplied callback table to check the VMM
- * version and to register its devices.  Each device has an unique (for the
- * configured VM) name.  The name is not only used in PDM but also in CFGM (to
- * organize device and device instance settings) and by anyone who wants to talk
- * to a specific device instance.
+ * version and to register its devices.  Each device has an unique name (within
+ * the VM configuration anyway).  The name is not only used in PDM, but also in
+ * CFGM to organize device and device instance settings, and by anyone who wants
+ * to talk to a specific device instance.
  *
  * When all device modules have been successfully loaded PDM will instantiate
  * those devices which are configured for the VM.  Note that a device may have
- * more than one instance, see network adaptors for instance.  When
+ * more than one instance, take network adaptors as an example.  When
  * instantiating a device PDM provides device instance memory and a callback
  * table (aka Device Helpers / DevHlp) with the VM APIs which the device
  * instance is trusted with.
  *
  * Some devices are trusted devices, most are not.  The trusted devices are an
- * integrated part of the VM and can obtain the VM handle from their device
- * instance handles, thus enabling them to call any VM API.  Untrusted devices
- * can only use the callbacks provided during device instantiation.
+ * integrated part of the VM and can obtain the VM handle, thus enabling them to
+ * call any VM API.  Untrusted devices can only use the callbacks provided
+ * during device instantiation.
  *
  * The main purpose in having DevHlps rather than just giving all the devices
  * the VM handle and let them call the internal VM APIs directly, is both to
@@ -73,6 +73,29 @@
  * will be subject to relocation.
  *
  *
+ * @subsection sec_pdm_dev_pci          PCI Devices
+ *
+ * A PDM device usually registers one a PCI device during it's instantiation,
+ * legacy devices may register zero, while a few (currently none) more
+ * complicated devices may register multiple PCI functions or devices.
+ *
+ * The bus, device and function assignments can either be done explictly via the
+ * configuration or the registration call, or it can be left up to the PCI bus.
+ * The typical VBox configuration construct (ConsoleImpl2.cpp) will do explict
+ * assignments for all devices it's BusAssignmentManager class knows about.
+ *
+ * For explict CFGM style configuration, the "PCIBusNo", "PCIDeviceNo", and
+ * "PCIFunctionNo" values in the PDM device instance configuration (not the
+ * "config" subkey, but the top level one) will be picked up for the primary PCI
+ * device.  The primary PCI configuration is by default the first one, but this
+ * can be controlled using the @a idxDevCfg parameter of the
+ * PDMDEVHLPR3::pfnPCIRegister method.  For subsequent configuration (@a
+ * idxDevCfg > 0) the values are taken from the "PciDevNN" subkey, where "NN" is
+ * replaced by the @a idxDevCfg value.
+ *
+ * There's currently a limit of 256 PCI devices per PDM device.
+ *
+ *
  * @section sec_pdm_special_devs    Special Devices
  *
  * Several kinds of devices interacts with the VMM and/or other device and PDM
@@ -253,6 +276,7 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_PDM
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
 #include "PDMInternal.h"
 #include <VBox/vmm/pdm.h>
 #include <VBox/vmm/em.h>
@@ -572,10 +596,21 @@ VMMR3_INT_DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
             if (pDevIns->pCritSectRoR3)
                 pDevIns->pCritSectRoRC  = MMHyperR3ToRC(pVM, pDevIns->pCritSectRoR3);
             pDevIns->Internal.s.pVMRC   = pVM->pVMRC;
-            if (pDevIns->Internal.s.pPciBusR3)
-                pDevIns->Internal.s.pPciBusRC    = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
-            if (pDevIns->Internal.s.pPciDeviceR3)
-                pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
+
+            PPDMPCIDEV pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+            if (pPciDev)
+            {
+                pDevIns->Internal.s.pHeadPciDevRC = MMHyperR3ToRC(pVM, pPciDev);
+                do
+                {
+                    pPciDev->Int.s.pDevInsRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pDevInsR3);
+                    pPciDev->Int.s.pPdmBusRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pPdmBusR3);
+                    if (pPciDev->Int.s.pNextR3)
+                        pPciDev->Int.s.pNextRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pNextR3);
+                    pPciDev = pPciDev->Int.s.pNextR3;
+                } while (pPciDev);
+            }
+
             if (pDevIns->pReg->pfnRelocate)
             {
                 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
@@ -738,7 +773,7 @@ VMMR3_INT_DECL(int) PDMR3Term(PVM pVM)
         pdmR3CritSectBothDeleteDevice(pVM, pDevIns);
         pdmR3ThreadDestroyDevice(pVM, pDevIns);
         PDMR3QueueDestroyDevice(pVM, pDevIns);
-        PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
+        PGMR3PhysMMIOExDeregister(pVM, pDevIns, UINT32_MAX, UINT32_MAX);
 #ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
         pdmR3AsyncCompletionTemplateDestroyDevice(pVM, pDevIns);
 #endif
diff --git a/src/VBox/VMM/VMMR3/PDMBlkCache.cpp b/src/VBox/VMM/VMMR3/PDMBlkCache.cpp
index ace04b3..47b7ace 100644
--- a/src/VBox/VMM/VMMR3/PDMBlkCache.cpp
+++ b/src/VBox/VMM/VMMR3/PDMBlkCache.cpp
@@ -1567,7 +1567,7 @@ static PPDMBLKCACHEENTRY pdmBlkCacheGetCacheEntryByOffset(PPDMBLKCACHE pBlkCache
  * @param   pBlkCache    The endpoint cache.
  * @param   off          The offset.
  * @param   ppEntryAbove Where to store the pointer to the best fit entry above
- *                       the the given offset. NULL if not required.
+ *                       the given offset. NULL if not required.
  */
 static void pdmBlkCacheGetCacheBestFitEntryByOffset(PPDMBLKCACHE pBlkCache, uint64_t off, PPDMBLKCACHEENTRY *ppEntryAbove)
 {
diff --git a/src/VBox/VMM/VMMR3/PDMDevHlp.cpp b/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
index 813e94f..d26b796 100644
--- a/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
+++ b/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
@@ -20,6 +20,7 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_PDM_DEVICE
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
 #include "PDMInternal.h"
 #include <VBox/vmm/pdm.h>
 #include <VBox/vmm/mm.h>
@@ -426,16 +427,20 @@ static DECLCALLBACK(int) pdmR3DevHlp_MMIODeregister(PPDMDEVINS pDevIns, RTGCPHYS
 /**
  * @copydoc PDMDEVHLPR3::pfnMMIO2Register
  */
-static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Register(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cb,
+                                                   uint32_t fFlags, void **ppv, const char *pszDesc)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-    LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: iRegion=%#x cb=%#RGp fFlags=%RX32 ppv=%p pszDescp=%p:{%s}\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion, cb, fFlags, ppv, pszDesc, pszDesc));
+    LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: pPciDev=%p (%#x) iRegion=%#x cb=%#RGp fFlags=%RX32 ppv=%p pszDescp=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion,
+             cb, fFlags, ppv, pszDesc, pszDesc));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
 
 /** @todo PGMR3PhysMMIO2Register mangles the description, move it here and
  *        use a real string cache. */
-    int rc = PGMR3PhysMMIO2Register(pDevIns->Internal.s.pVMR3, pDevIns, iRegion, cb, fFlags, ppv, pszDesc);
+    int rc = PGMR3PhysMMIO2Register(pDevIns->Internal.s.pVMR3, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion,
+                                    cb, fFlags, ppv, pszDesc);
 
     LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
     return rc;
@@ -443,54 +448,148 @@ static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Register(PPDMDEVINS pDevIns, uint32_t
 
 
 /**
- * @copydoc PDMDEVHLPR3::pfnMMIO2Deregister
+ * @interface_method_impl{PDMDEVHLPR3,pfnMMIOExPreRegister}
  */
-static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion)
+static DECLCALLBACK(int)
+pdmR3DevHlp_MMIOExPreRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion, uint32_t fFlags,
+                              const char *pszDesc,
+                              RTHCPTR pvUser, PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
+                              RTR0PTR pvUserR0, const char *pszWriteR0, const char *pszReadR0, const char *pszFillR0,
+                              RTRCPTR pvUserRC, const char *pszWriteRC, const char *pszReadRC, const char *pszFillRC)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT(pVM);
+    LogFlow(("pdmR3DevHlp_MMIOExPreRegister: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x cbRegion=%#RGp fFlags=%RX32 pszDesc=%p:{%s}\n"
+             "                               pvUser=%p pfnWrite=%p pfnRead=%p pfnFill=%p\n"
+             "                               pvUserR0=%p pszWriteR0=%s pszReadR0=%s pszFillR0=%s\n"
+             "                               pvUserRC=%p pszWriteRC=%s pszReadRC=%s pszFillRC=%s\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, cbRegion,
+             fFlags, pszDesc, pszDesc,
+             pvUser, pfnWrite, pfnRead, pfnFill,
+             pvUserR0, pszWriteR0, pszReadR0, pszFillR0,
+             pvUserRC, pszWriteRC, pszReadRC, pszFillRC));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
+
+    /*
+     * Resolve the functions.
+     */
+    AssertLogRelReturn(   (!pszWriteR0 && !pszReadR0 && !pszFillR0)
+                       || (pDevIns->pReg->szR0Mod[0] && (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)),
+                       VERR_INVALID_PARAMETER);
+    AssertLogRelReturn(   (!pszWriteRC && !pszReadRC && !pszFillRC)
+                       || (pDevIns->pReg->szRCMod[0] && (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)),
+                       VERR_INVALID_PARAMETER);
+
+    /* Ring-0 */
+    int rc;
+    R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteR0 = 0;
+    if (pszWriteR0)
+    {
+        rc = pdmR3DevGetSymbolR0Lazy(pDevIns, pszWriteR0, &pfnWriteR0);
+        AssertLogRelMsgRCReturn(rc, ("pszWriteR0=%s rc=%Rrc\n", pszWriteR0, rc), rc);
+    }
+
+    R0PTRTYPE(PFNIOMMMIOREAD) pfnReadR0 = 0;
+    if (pszReadR0)
+    {
+        rc = pdmR3DevGetSymbolR0Lazy(pDevIns, pszReadR0, &pfnReadR0);
+        AssertLogRelMsgRCReturn(rc, ("pszReadR0=%s rc=%Rrc\n", pszReadR0, rc), rc);
+    }
+    R0PTRTYPE(PFNIOMMMIOFILL) pfnFillR0 = 0;
+    if (pszFillR0)
+    {
+        rc = pdmR3DevGetSymbolR0Lazy(pDevIns, pszFillR0, &pfnFillR0);
+        AssertLogRelMsgRCReturn(rc, ("pszFillR0=%s rc=%Rrc\n", pszFillR0, rc), rc);
+    }
+
+    /* Raw-mode */
+    rc = VINF_SUCCESS;
+    RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteRC = 0;
+    if (pszWriteRC)
+    {
+        rc = pdmR3DevGetSymbolRCLazy(pDevIns, pszWriteRC, &pfnWriteRC);
+        AssertLogRelMsgRCReturn(rc, ("pszWriteRC=%s rc=%Rrc\n", pszWriteRC, rc), rc);
+    }
+
+    RCPTRTYPE(PFNIOMMMIOREAD) pfnReadRC = 0;
+    if (pszReadRC)
+    {
+        rc = pdmR3DevGetSymbolRCLazy(pDevIns, pszReadRC, &pfnReadRC);
+        AssertLogRelMsgRCReturn(rc, ("pszReadRC=%s rc=%Rrc\n", pszReadRC, rc), rc);
+    }
+    RCPTRTYPE(PFNIOMMMIOFILL) pfnFillRC = 0;
+    if (pszFillRC)
+    {
+        rc = pdmR3DevGetSymbolRCLazy(pDevIns, pszFillRC, &pfnFillRC);
+        AssertLogRelMsgRCReturn(rc, ("pszFillRC=%s rc=%Rrc\n", pszFillRC, rc), rc);
+    }
+
+    /*
+     * Call IOM to make the registration.
+     */
+    rc = IOMR3MmioExPreRegister(pVM, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion, cbRegion, fFlags, pszDesc,
+                                pvUser,   pfnWrite,   pfnRead,   pfnFill,
+                                pvUserR0, pfnWriteR0, pfnReadR0, pfnFillR0,
+                                pvUserRC, pfnWriteRC, pfnReadRC, pfnFillRC);
+
+    LogFlow(("pdmR3DevHlp_MMIOExPreRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExDeregister
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExDeregister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-    LogFlow(("pdmR3DevHlp_MMIO2Deregister: caller='%s'/%d: iRegion=%#x\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion));
+    LogFlow(("pdmR3DevHlp_MMIOExDeregister: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion));
 
     AssertReturn(iRegion <= UINT8_MAX || iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
 
-    int rc = PGMR3PhysMMIO2Deregister(pDevIns->Internal.s.pVMR3, pDevIns, iRegion);
+    int rc = PGMR3PhysMMIOExDeregister(pDevIns->Internal.s.pVMR3, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion);
 
-    LogFlow(("pdmR3DevHlp_MMIO2Deregister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    LogFlow(("pdmR3DevHlp_MMIOExDeregister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
     return rc;
 }
 
 
 /**
- * @copydoc PDMDEVHLPR3::pfnMMIO2Map
+ * @copydoc PDMDEVHLPR3::pfnMMIOExMap
  */
-static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-    LogFlow(("pdmR3DevHlp_MMIO2Map: caller='%s'/%d: iRegion=%#x GCPhys=%#RGp\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion, GCPhys));
+    LogFlow(("pdmR3DevHlp_MMIOExMap: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x GCPhys=%#RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, GCPhys));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 != NULL, VERR_INVALID_PARAMETER);
 
-    int rc = PGMR3PhysMMIO2Map(pDevIns->Internal.s.pVMR3, pDevIns, iRegion, GCPhys);
+    int rc = PGMR3PhysMMIOExMap(pDevIns->Internal.s.pVMR3, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion, GCPhys);
 
-    LogFlow(("pdmR3DevHlp_MMIO2Map: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    LogFlow(("pdmR3DevHlp_MMIOExMap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
     return rc;
 }
 
 
 /**
- * @copydoc PDMDEVHLPR3::pfnMMIO2Unmap
+ * @copydoc PDMDEVHLPR3::pfnMMIOExUnmap
  */
-static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExUnmap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-    LogFlow(("pdmR3DevHlp_MMIO2Unmap: caller='%s'/%d: iRegion=%#x GCPhys=%#RGp\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion, GCPhys));
+    LogFlow(("pdmR3DevHlp_MMIOExUnmap: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x GCPhys=%#RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, GCPhys));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 != NULL, VERR_INVALID_PARAMETER);
 
-    int rc = PGMR3PhysMMIO2Unmap(pDevIns->Internal.s.pVMR3, pDevIns, iRegion, GCPhys);
+    int rc = PGMR3PhysMMIOExUnmap(pDevIns->Internal.s.pVMR3, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion, GCPhys);
 
-    LogFlow(("pdmR3DevHlp_MMIO2Unmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    LogFlow(("pdmR3DevHlp_MMIOExUnmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
     return rc;
 }
 
@@ -498,14 +597,15 @@ static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRe
 /**
  * @copydoc PDMDEVHLPR3::pfnMMHyperMapMMIO2
  */
-static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
-                                                     const char *pszDesc, PRTRCPTR pRCPtr)
+static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off,
+                                                     RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     PVM pVM = pDevIns->Internal.s.pVMR3;
     VM_ASSERT_EMT(pVM);
-    LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pRCPtr=%p\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion, off, cb, pszDesc, pszDesc, pRCPtr));
+    LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pRCPtr=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, off, cb, pszDesc, pszDesc, pRCPtr));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
 
     if (pDevIns->iInstance > 0)
     {
@@ -514,7 +614,7 @@ static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_
              pszDesc = pszDesc2;
     }
 
-    int rc = MMR3HyperMapMMIO2(pVM, pDevIns, iRegion, off, cb, pszDesc, pRCPtr);
+    int rc = MMR3HyperMapMMIO2(pVM, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion, off, cb, pszDesc, pRCPtr);
 
     LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: returns %Rrc *pRCPtr=%RRv\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *pRCPtr));
     return rc;
@@ -524,14 +624,15 @@ static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_
 /**
  * @copydoc PDMDEVHLPR3::pfnMMIO2MapKernel
  */
-static DECLCALLBACK(int) pdmR3DevHlp_MMIO2MapKernel(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
-                                                    const char *pszDesc, PRTR0PTR pR0Ptr)
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2MapKernel(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off,
+                                                    RTGCPHYS cb,const char *pszDesc, PRTR0PTR pR0Ptr)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     PVM pVM = pDevIns->Internal.s.pVMR3;
     VM_ASSERT_EMT(pVM);
-    LogFlow(("pdmR3DevHlp_MMIO2MapKernel: caller='%s'/%d: iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pR0Ptr=%p\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion, off, cb, pszDesc, pszDesc, pR0Ptr));
+    LogFlow(("pdmR3DevHlp_MMIO2MapKernel: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pR0Ptr=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, off, cb, pszDesc, pszDesc, pR0Ptr));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
 
     if (pDevIns->iInstance > 0)
     {
@@ -540,7 +641,7 @@ static DECLCALLBACK(int) pdmR3DevHlp_MMIO2MapKernel(PPDMDEVINS pDevIns, uint32_t
              pszDesc = pszDesc2;
     }
 
-    int rc = PGMR3PhysMMIO2MapKernel(pVM, pDevIns, iRegion, off, cb, pszDesc, pR0Ptr);
+    int rc = PGMR3PhysMMIO2MapKernel(pVM, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion, off, cb, pszDesc, pR0Ptr);
 
     LogFlow(("pdmR3DevHlp_MMIO2MapKernel: caller='%s'/%d: returns %Rrc *pR0Ptr=%RHv\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *pR0Ptr));
     return rc;
@@ -1110,39 +1211,116 @@ static DECLCALLBACK(void) pdmR3DevHlp_STAMRegisterV(PPDMDEVINS pDevIns, void *pv
 }
 
 
-/** @interface_method_impl{PDMDEVHLPR3,pfnPCIRegister} */
-static DECLCALLBACK(int) pdmR3DevHlp_PCIRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev)
+/**
+ * @interface_method_impl{PDMDEVHLPR3,pfnPCIRegister}
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t idxDevCfg, uint32_t fFlags,
+                                                 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     PVM pVM = pDevIns->Internal.s.pVMR3;
     VM_ASSERT_EMT(pVM);
-    LogFlow(("pdmR3DevHlp_PCIRegister: caller='%s'/%d: pPciDev=%p:{.config={%#.256Rhxs}\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->config));
+    LogFlow(("pdmR3DevHlp_PCIRegister: caller='%s'/%d: pPciDev=%p:{.config={%#.256Rhxs} idxDevCfg=%d fFlags=%#x uPciDevNo=%#x uPciFunNo=%#x pszName=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->abConfig, idxDevCfg, fFlags, uPciDevNo, uPciFunNo, pszName, pszName ? pszName : ""));
 
     /*
      * Validate input.
      */
-    if (!pPciDev)
-    {
-        Assert(pPciDev);
-        LogFlow(("pdmR3DevHlp_PCIRegister: caller='%s'/%d: returns %Rrc (pPciDev)\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
-        return VERR_INVALID_PARAMETER;
+    AssertLogRelMsgReturn(RT_VALID_PTR(pPciDev),
+                          ("'%s'/%d: Invalid pPciDev value: %p\n", pDevIns->pReg->szName, pDevIns->iInstance, pPciDev),
+                          VERR_INVALID_POINTER);
+    AssertLogRelMsgReturn(PDMPciDevGetVendorId(pPciDev),
+                          ("'%s'/%d: Vendor ID is not set!\n", pDevIns->pReg->szName, pDevIns->iInstance),
+                          VERR_INVALID_POINTER);
+    AssertLogRelMsgReturn(idxDevCfg < 256 || idxDevCfg == PDMPCIDEVREG_CFG_NEXT,
+                          ("'%s'/%d: Invalid config selector: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
+                          VERR_OUT_OF_RANGE);
+    AssertLogRelMsgReturn(   uPciDevNo < 32
+                          || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED
+                          || uPciDevNo == PDMPCIDEVREG_DEV_NO_SAME_AS_PREV,
+                          ("'%s'/%d: Invalid PCI device number: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, uPciDevNo),
+                          VERR_INVALID_PARAMETER);
+    AssertLogRelMsgReturn(   uPciFunNo < 8
+                          || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED,
+                          ("'%s'/%d: Invalid PCI funcion number: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, uPciFunNo),
+                          VERR_INVALID_PARAMETER);
+    AssertLogRelMsgReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK),
+                          ("'%s'/%d: Invalid flags: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, fFlags),
+                          VERR_INVALID_FLAGS);
+    if (!pszName)
+        pszName = pDevIns->pReg->szName;
+    AssertLogRelReturn(RT_VALID_PTR(pszName), VERR_INVALID_POINTER);
+
+    /*
+     * Find the last(/previous) registered PCI device (for linking and more),
+     * checking for duplicate registration attempts while doing so.
+     */
+    uint32_t idxDevCfgNext = 0;
+    PPDMPCIDEV pPrevPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    while (pPrevPciDev)
+    {
+        AssertLogRelMsgReturn(pPrevPciDev != pPciDev,
+                              ("'%s'/%d attempted to register the same PCI device (%p) twice\n",
+                               pDevIns->pReg->szName, pDevIns->iInstance, pPciDev),
+                              VERR_DUPLICATE);
+        AssertLogRelMsgReturn(pPrevPciDev->Int.s.idxDevCfg != idxDevCfg,
+                              ("'%s'/%d attempted to use the same device config index (%u) twice\n",
+                               pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
+                              VERR_ALREADY_LOADED);
+        if (pPrevPciDev->Int.s.idxDevCfg >= idxDevCfgNext)
+            idxDevCfgNext = pPrevPciDev->Int.s.idxDevCfg + 1;
+
+        if (!pPrevPciDev->Int.s.pNextR3)
+            break;
+        pPrevPciDev = pPrevPciDev->Int.s.pNextR3;
     }
-    if (!pPciDev->config[0] && !pPciDev->config[1])
+
+    /*
+     * Resolve the PCI configuration node for the device.  The default (zero'th)
+     * is the same as the PDM device, the rest are "PciCfg1..255" CFGM sub-nodes.
+     */
+    if (idxDevCfg == PDMPCIDEVREG_CFG_NEXT)
     {
-        Assert(pPciDev->config[0] || pPciDev->config[1]);
-        LogFlow(("pdmR3DevHlp_PCIRegister: caller='%s'/%d: returns %Rrc (vendor)\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
-        return VERR_INVALID_PARAMETER;
+        idxDevCfg = idxDevCfgNext;
+        AssertLogRelMsgReturn(idxDevCfg < 256, ("'%s'/%d: PDMPCIDEVREG_IDX_DEV_CFG_NEXT ran out of valid indexes (ends at 255)\n",
+                                                pDevIns->pReg->szName, pDevIns->iInstance),
+                              VERR_OUT_OF_RANGE);
     }
-    if (pDevIns->Internal.s.pPciDeviceR3)
+
+    PCFGMNODE pCfg = pDevIns->Internal.s.pCfgHandle;
+    if (idxDevCfg != 0)
+        pCfg = CFGMR3GetChildF(pDevIns->Internal.s.pCfgHandle, "PciCfg%u", idxDevCfg);
+
+    /*
+     * We resolve PDMPCIDEVREG_DEV_NO_SAME_AS_PREV, the PCI bus handles
+     * PDMPCIDEVREG_DEV_NO_FIRST_UNUSED and PDMPCIDEVREG_FUN_NO_FIRST_UNUSED.
+     */
+    uint8_t const uPciDevNoRaw = uPciDevNo;
+    if (uPciDevNo == PDMPCIDEVREG_DEV_NO_SAME_AS_PREV)
     {
-        /** @todo the PCI device vs. PDM device designed is a bit flawed if we have to
-         * support a PDM device with multiple PCI devices. This might become a problem
-         * when upgrading the chipset for instance because of multiple functions in some
-         * devices...
-         */
-        AssertMsgFailed(("Only one PCI device per device is currently implemented!\n"));
-        return VERR_PDM_ONE_PCI_FUNCTION_PER_DEVICE;
+        if (pPrevPciDev)
+            uPciDevNo = pPrevPciDev->uDevFn >> 3;
+        else
+        {
+            /* Look for PCI device registered with an earlier device instance so we can more
+               easily have multiple functions spanning multiple PDM device instances. */
+            PPDMPCIDEV pOtherPciDev = NULL;
+            PPDMDEVINS pPrevIns = pDevIns->Internal.s.pDevR3->pInstances;
+            while (pPrevIns != pDevIns && pPrevIns)
+            {
+                pOtherPciDev = pPrevIns->Internal.s.pHeadPciDevR3;
+                pPrevIns = pPrevIns->Internal.s.pNextR3;
+            }
+            Assert(pPrevIns == pDevIns);
+            AssertLogRelMsgReturn(pOtherPciDev,
+                                  ("'%s'/%d: Can't use PDMPCIDEVREG_DEV_NO_SAME_AS_PREV without a previously registered PCI device by the same or earlier PDM device instance!\n",
+                                   pDevIns->pReg->szName, pDevIns->iInstance),
+                                  VERR_WRONG_ORDER);
+
+            while (pOtherPciDev->Int.s.pNextR3)
+                pOtherPciDev = pOtherPciDev->Int.s.pNextR3;
+            uPciDevNo = pOtherPciDev->uDevFn >> 3;
+        }
     }
 
     /*
@@ -1151,87 +1329,139 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIRegister(PPDMDEVINS pDevIns, PPCIDEVICE
      * This is simple. If the device was configured for a particular bus, the PCIBusNo
      * configuration value will be set. If not the default bus is 0.
      */
-    int rc;
-    PPDMPCIBUS pBus = pDevIns->Internal.s.pPciBusR3;
-    if (!pBus)
-    {
-        uint8_t u8Bus;
-        rc = CFGMR3QueryU8Def(pDevIns->Internal.s.pCfgHandle, "PCIBusNo", &u8Bus, 0);
-        AssertLogRelMsgRCReturn(rc, ("Configuration error: PCIBusNo query failed with rc=%Rrc (%s/%d)\n",
-                                     rc, pDevIns->pReg->szName, pDevIns->iInstance), rc);
-        AssertLogRelMsgReturn(u8Bus < RT_ELEMENTS(pVM->pdm.s.aPciBuses),
-                              ("Configuration error: PCIBusNo=%d, max is %d. (%s/%d)\n", u8Bus,
-                               RT_ELEMENTS(pVM->pdm.s.aPciBuses), pDevIns->pReg->szName, pDevIns->iInstance),
-                              VERR_PDM_NO_PCI_BUS);
-        pBus = pDevIns->Internal.s.pPciBusR3 = &pVM->pdm.s.aPciBuses[u8Bus];
-    }
+    /** @cfgm{/Devices/NAME/XX/[PciCfgYY/]PCIBusNo, uint8_t, 0, 7, 0}
+     * Selects the PCI bus number of a device.
+     */
+    uint8_t u8Bus;
+    int rc = CFGMR3QueryU8Def(pCfg, "PCIBusNo", &u8Bus, 0);
+    AssertLogRelMsgRCReturn(rc, ("Configuration error: PCIBusNo query failed with rc=%Rrc (%s/%d)\n",
+                                 rc, pDevIns->pReg->szName, pDevIns->iInstance), rc);
+    AssertLogRelMsgReturn(u8Bus < RT_ELEMENTS(pVM->pdm.s.aPciBuses),
+                          ("Configuration error: PCIBusNo=%d, max is %d. (%s/%d)\n", u8Bus,
+                           RT_ELEMENTS(pVM->pdm.s.aPciBuses), pDevIns->pReg->szName, pDevIns->iInstance),
+                          VERR_PDM_NO_PCI_BUS);
+    PPDMPCIBUS pBus = pPciDev->Int.s.pPdmBusR3 = &pVM->pdm.s.aPciBuses[u8Bus];
     if (pBus->pDevInsR3)
     {
-        if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)
-            pDevIns->Internal.s.pPciBusR0 = MMHyperR3ToR0(pVM, pDevIns->Internal.s.pPciBusR3);
-        else
-            pDevIns->Internal.s.pPciBusR0 = NIL_RTR0PTR;
-
-        if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
-            pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
-        else
-            pDevIns->Internal.s.pPciBusRC = NIL_RTRCPTR;
-
         /*
          * Check the configuration for PCI device and function assignment.
          */
-        int iDev = -1;
-        uint8_t     u8Device;
-        rc = CFGMR3QueryU8(pDevIns->Internal.s.pCfgHandle, "PCIDeviceNo", &u8Device);
+        /** @cfgm{/Devices/NAME/XX/[PciCfgYY/]PCIDeviceNo, uint8_t, 0, 31}
+         * Overrides the default PCI device number of a device.
+         */
+        uint8_t uCfgDevice;
+        rc = CFGMR3QueryU8(pCfg, "PCIDeviceNo", &uCfgDevice);
         if (RT_SUCCESS(rc))
         {
-            AssertMsgReturn(u8Device <= 31,
-                            ("Configuration error: PCIDeviceNo=%d, max is 31. (%s/%d)\n",
-                             u8Device, pDevIns->pReg->szName, pDevIns->iInstance),
+            AssertMsgReturn(uCfgDevice <= 31,
+                            ("Configuration error: PCIDeviceNo=%d, max is 31. (%s/%d/%d)\n",
+                             uCfgDevice, pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
                             VERR_PDM_BAD_PCI_CONFIG);
+            uPciDevNo = uCfgDevice;
+        }
+        else
+            AssertMsgReturn(rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT,
+                            ("Configuration error: PCIDeviceNo query failed with rc=%Rrc (%s/%d/%d)\n",
+                             rc, pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
+                            rc);
 
-            uint8_t u8Function;
-            rc = CFGMR3QueryU8(pDevIns->Internal.s.pCfgHandle, "PCIFunctionNo", &u8Function);
-            AssertMsgRCReturn(rc, ("Configuration error: PCIDeviceNo, but PCIFunctionNo query failed with rc=%Rrc (%s/%d)\n",
-                                   rc, pDevIns->pReg->szName, pDevIns->iInstance),
-                              rc);
-            AssertMsgReturn(u8Function <= 7,
-                            ("Configuration error: PCIFunctionNo=%d, max is 7. (%s/%d)\n",
-                             u8Function, pDevIns->pReg->szName, pDevIns->iInstance),
+        /** @cfgm{/Devices/NAME/XX/[PciCfgYY/]PCIFunctionNo, uint8_t, 0, 7}
+         * Overrides the default PCI function number of a device.
+         */
+        uint8_t uCfgFunction;
+        rc = CFGMR3QueryU8(pCfg, "PCIFunctionNo", &uCfgFunction);
+        if (RT_SUCCESS(rc))
+        {
+            AssertMsgReturn(uCfgFunction <= 7,
+                            ("Configuration error: PCIFunctionNo=%#x, max is 7. (%s/%d/%d)\n",
+                             uCfgFunction, pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
                             VERR_PDM_BAD_PCI_CONFIG);
+            uPciFunNo = uCfgFunction;
+        }
+        else
+            AssertMsgReturn(rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT,
+                            ("Configuration error: PCIFunctionNo query failed with rc=%Rrc (%s/%d/%d)\n",
+                             rc, pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
+                            rc);
+
+
+        /*
+         * Initialize the internal data.  We only do the wipe and the members
+         * owned by PDM, the PCI bus does the rest in the registration call.
+         */
+        RT_ZERO(pPciDev->Int);
+
+        pPciDev->Int.s.idxDevCfg = idxDevCfg;
+        pPciDev->Int.s.fReassignableDevNo = uPciDevNoRaw >= VBOX_PCI_MAX_DEVICES;
+        pPciDev->Int.s.fReassignableFunNo = uPciFunNo >= VBOX_PCI_MAX_FUNCTIONS;
+        pPciDev->Int.s.pDevInsR3 = pDevIns;
+        pPciDev->Int.s.pPdmBusR3 = pBus;
+        if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)
+        {
+            pPciDev->Int.s.pDevInsR0 = MMHyperR3ToR0(pVM, pDevIns);
+            pPciDev->Int.s.pPdmBusR0 = MMHyperR3ToR0(pVM, pBus);
+        }
+        else
+        {
+            pPciDev->Int.s.pDevInsR0 = NIL_RTR0PTR;
+            pPciDev->Int.s.pPdmBusR0 = NIL_RTR0PTR;
+        }
 
-            iDev = (u8Device << 3) | u8Function;
+        if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
+        {
+            pPciDev->Int.s.pDevInsRC = MMHyperR3ToRC(pVM, pDevIns);
+            pPciDev->Int.s.pPdmBusRC = MMHyperR3ToRC(pVM, pBus);
         }
-        else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
+        else
         {
-            AssertMsgFailed(("Configuration error: PCIDeviceNo query failed with rc=%Rrc (%s/%d)\n",
-                             rc, pDevIns->pReg->szName, pDevIns->iInstance));
-            return rc;
+            pPciDev->Int.s.pDevInsRC = NIL_RTRCPTR;
+            pPciDev->Int.s.pPdmBusRC = NIL_RTRCPTR;
         }
 
+        /* Set some of the public members too. */
+        pPciDev->pszNameR3 = pszName;
+
         /*
          * Call the pci bus device to do the actual registration.
          */
         pdmLock(pVM);
-        rc = pBus->pfnRegisterR3(pBus->pDevInsR3, pPciDev, pDevIns->pReg->szName, iDev);
+        rc = pBus->pfnRegisterR3(pBus->pDevInsR3, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
         pdmUnlock(pVM);
         if (RT_SUCCESS(rc))
         {
-            pPciDev->pDevIns = pDevIns;
-
-            pDevIns->Internal.s.pPciDeviceR3 = pPciDev;
-            if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)
-                pDevIns->Internal.s.pPciDeviceR0 = MMHyperR3ToR0(pVM, pPciDev);
-            else
-                pDevIns->Internal.s.pPciDeviceR0 = NIL_RTR0PTR;
 
-            if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
-                pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pPciDev);
+            /*
+             * Link it.
+             */
+            if (pPrevPciDev)
+            {
+                Assert(!pPrevPciDev->Int.s.pNextR3);
+                pPrevPciDev->Int.s.pNextR3 = pPciDev;
+                if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)
+                    pPrevPciDev->Int.s.pNextR0 = MMHyperR3ToR0(pVM, pPciDev);
+                else
+                    pPrevPciDev->Int.s.pNextR0 = NIL_RTR0PTR;
+                if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
+                    pPrevPciDev->Int.s.pNextRC = MMHyperR3ToRC(pVM, pPciDev);
+                else
+                    pPrevPciDev->Int.s.pNextRC = NIL_RTRCPTR;
+            }
             else
-                pDevIns->Internal.s.pPciDeviceRC = NIL_RTRCPTR;
+            {
+                Assert(!pDevIns->Internal.s.pHeadPciDevR3);
+                pDevIns->Internal.s.pHeadPciDevR3 = pPciDev;
+                if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)
+                    pDevIns->Internal.s.pHeadPciDevR0 = MMHyperR3ToR0(pVM, pPciDev);
+                else
+                    pDevIns->Internal.s.pHeadPciDevR0 = NIL_RTR0PTR;
+                if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
+                    pDevIns->Internal.s.pHeadPciDevRC = MMHyperR3ToRC(pVM, pPciDev);
+                else
+                    pDevIns->Internal.s.pHeadPciDevRC = NIL_RTRCPTR;
+            }
 
             Log(("PDM: Registered device '%s'/%d as PCI device %d on bus %d\n",
-                 pDevIns->pReg->szName, pDevIns->iInstance, pPciDev->devfn, pDevIns->Internal.s.pPciBusR3->iBus));
+                 pDevIns->pReg->szName, pDevIns->iInstance, pPciDev->uDevFn, pBus->iBus));
         }
     }
     else
@@ -1245,22 +1475,50 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIRegister(PPDMDEVINS pDevIns, PPCIDEVICE
 }
 
 
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCIRegisterMsi} */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIRegisterMsi(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
+    LogFlow(("pdmR3DevHlp_PCIRegisterMsi: caller='%s'/%d: pPciDev=%p:{%#x} pMsgReg=%p:{cMsiVectors=%d, cMsixVectors=%d}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, pMsiReg, pMsiReg->cMsiVectors, pMsiReg->cMsixVectors));
+
+    PPDMPCIBUS pBus = pPciDev->Int.s.pPdmBusR3; Assert(pBus);
+    PVM        pVM  = pDevIns->Internal.s.pVMR3;
+    pdmLock(pVM);
+    int rc;
+    if (pBus->pfnRegisterMsiR3)
+        rc = pBus->pfnRegisterMsiR3(pBus->pDevInsR3, pPciDev, pMsiReg);
+    else
+        rc = VERR_NOT_IMPLEMENTED;
+    pdmUnlock(pVM);
+
+    LogFlow(("pdmR3DevHlp_PCIRegisterMsi: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
 /** @interface_method_impl{PDMDEVHLPR3,pfnPCIIORegionRegister} */
-static DECLCALLBACK(int) pdmR3DevHlp_PCIIORegionRegister(PPDMDEVINS pDevIns, int iRegion, RTGCPHYS cbRegion,
-                                                         PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
+static DECLCALLBACK(int) pdmR3DevHlp_PCIIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                                         RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     PVM pVM = pDevIns->Internal.s.pVMR3;
     VM_ASSERT_EMT(pVM);
-    LogFlow(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: iRegion=%d cbRegion=%RGp enmType=%d pfnCallback=%p\n",
-             pDevIns->pReg->szName, pDevIns->iInstance, iRegion, cbRegion, enmType, pfnCallback));
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
+    LogFlow(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%d cbRegion=%RGp enmType=%d pfnCallback=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iRegion, cbRegion, enmType, pfnCallback));
 
     /*
      * Validate input.
      */
-    if (iRegion < 0 || iRegion >= PCI_NUM_REGIONS)
+    if (iRegion >= VBOX_PCI_NUM_REGIONS)
     {
-        Assert(iRegion >= 0 && iRegion < PCI_NUM_REGIONS);
+        Assert(iRegion < VBOX_PCI_NUM_REGIONS);
         LogFlow(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: returns %Rrc (iRegion)\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
         return VERR_INVALID_PARAMETER;
     }
@@ -1281,8 +1539,9 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIIORegionRegister(PPDMDEVINS pDevIns, int
             /*
              * Sanity check: Don't allow to register more than 2GB of the PCI MMIO space.
              */
-            AssertLogRelMsgReturn(cbRegion <= _2G,
-                                  ("caller='%s'/%d: %RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, cbRegion),
+            AssertLogRelMsgReturn(cbRegion <= MM_MMIO_32_MAX,
+                                  ("caller='%s'/%d: %RGp (max %RGp)\n",
+                                   pDevIns->pReg->szName, pDevIns->iInstance, cbRegion, (RTGCPHYS)MM_MMIO_32_MAX),
                                   VERR_OUT_OF_RANGE);
             break;
 
@@ -1291,8 +1550,9 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIIORegionRegister(PPDMDEVINS pDevIns, int
             /*
              * Sanity check: Don't allow to register more than 64GB of the 64-bit PCI MMIO space.
              */
-            AssertLogRelMsgReturn(cbRegion <= 64*_1G64,
-                                  ("caller='%s'/%d: %RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, cbRegion),
+            AssertLogRelMsgReturn(cbRegion <= MM_MMIO_64_MAX,
+                                  ("caller='%s'/%d: %RGp (max %RGp)\n",
+                                   pDevIns->pReg->szName, pDevIns->iInstance, cbRegion, MM_MMIO_64_MAX),
                                   VERR_OUT_OF_RANGE);
             break;
 
@@ -1310,56 +1570,46 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIIORegionRegister(PPDMDEVINS pDevIns, int
     AssertRelease(VMR3GetState(pVM) != VMSTATE_RUNNING);
 
     /*
-     * Must have a PCI device registered!
+     * We're currently restricted to page aligned MMIO regions.
      */
-    int rc;
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR3;
-    if (pPciDev)
+    if (   ((enmType & ~(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_MEM_PREFETCH)) == PCI_ADDRESS_SPACE_MEM)
+        && cbRegion != RT_ALIGN_64(cbRegion, PAGE_SIZE))
     {
-        /*
-         * We're currently restricted to page aligned MMIO regions.
-         */
-        if (   ((enmType & ~(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_MEM_PREFETCH)) == PCI_ADDRESS_SPACE_MEM)
-            && cbRegion != RT_ALIGN_64(cbRegion, PAGE_SIZE))
-        {
-            Log(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: aligning cbRegion %RGp -> %RGp\n",
-                 pDevIns->pReg->szName, pDevIns->iInstance, cbRegion, RT_ALIGN_64(cbRegion, PAGE_SIZE)));
-            cbRegion = RT_ALIGN_64(cbRegion, PAGE_SIZE);
-        }
-
-        /*
-         * For registering PCI MMIO memory or PCI I/O memory, the size of the region must be a power of 2!
-         */
-        int iLastSet = ASMBitLastSetU64(cbRegion);
-        Assert(iLastSet > 0);
-        uint64_t cbRegionAligned = RT_BIT_64(iLastSet - 1);
-        if (cbRegion > cbRegionAligned)
-            cbRegion = cbRegionAligned * 2; /* round up */
-
-        PPDMPCIBUS pBus = pDevIns->Internal.s.pPciBusR3;
-        Assert(pBus);
-        pdmLock(pVM);
-        rc = pBus->pfnIORegionRegisterR3(pBus->pDevInsR3, pPciDev, iRegion, cbRegion, enmType, pfnCallback);
-        pdmUnlock(pVM);
-    }
-    else
-    {
-        AssertMsgFailed(("No PCI device registered!\n"));
-        rc = VERR_PDM_NOT_PCI_DEVICE;
+        Log(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: aligning cbRegion %RGp -> %RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, cbRegion, RT_ALIGN_64(cbRegion, PAGE_SIZE)));
+        cbRegion = RT_ALIGN_64(cbRegion, PAGE_SIZE);
     }
 
+    /*
+     * For registering PCI MMIO memory or PCI I/O memory, the size of the region must be a power of 2!
+     */
+    int iLastSet = ASMBitLastSetU64(cbRegion);
+    Assert(iLastSet > 0);
+    uint64_t cbRegionAligned = RT_BIT_64(iLastSet - 1);
+    if (cbRegion > cbRegionAligned)
+        cbRegion = cbRegionAligned * 2; /* round up */
+
+    PPDMPCIBUS pBus = pPciDev->Int.s.pPdmBusR3;
+    Assert(pBus);
+    pdmLock(pVM);
+    int rc = pBus->pfnIORegionRegisterR3(pBus->pDevInsR3, pPciDev, iRegion, cbRegion, enmType, pfnCallback);
+    pdmUnlock(pVM);
+
     LogFlow(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
     return rc;
 }
 
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnPCISetConfigCallbacks} */
-static DECLCALLBACK(void) pdmR3DevHlp_PCISetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
+static DECLCALLBACK(void) pdmR3DevHlp_PCISetConfigCallbacks(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                                                             PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     PVM pVM = pDevIns->Internal.s.pVMR3;
     VM_ASSERT_EMT(pVM);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    AssertReturnVoid(pPciDev);
     LogFlow(("pdmR3DevHlp_PCISetConfigCallbacks: caller='%s'/%d: pPciDev=%p pfnRead=%p ppfnReadOld=%p pfnWrite=%p ppfnWriteOld=%p\n",
              pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pfnRead, ppfnReadOld, pfnWrite, ppfnWriteOld));
 
@@ -1372,10 +1622,7 @@ static DECLCALLBACK(void) pdmR3DevHlp_PCISetConfigCallbacks(PPDMDEVINS pDevIns,
     AssertPtrNull(ppfnWriteOld);
     AssertPtrNull(pPciDev);
 
-    if (!pPciDev)
-        pPciDev = pDevIns->Internal.s.pPciDeviceR3;
-    AssertReleaseMsg(pPciDev, ("You must register your device first!\n"));
-    PPDMPCIBUS pBus = pDevIns->Internal.s.pPciBusR3;
+    PPDMPCIBUS pBus = pPciDev->Int.s.pPdmBusR3;
     AssertRelease(pBus);
     AssertRelease(VMR3GetState(pVM) != VMSTATE_RUNNING);
 
@@ -1391,18 +1638,21 @@ static DECLCALLBACK(void) pdmR3DevHlp_PCISetConfigCallbacks(PPDMDEVINS pDevIns,
 
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnPCIPhysRead} */
-static DECLCALLBACK(int) pdmR3DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+static DECLCALLBACK(int)
+pdmR3DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
 
 #ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
     /*
      * Just check the busmaster setting here and forward the request to the generic read helper.
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR3;
-    AssertReleaseMsg(pPciDev, ("No PCI device registered!\n"));
-
-    if (!PCIDevIsBusmaster(pPciDev))
+    if (PCIDevIsBusmaster(pPciDev))
+    { /* likely */ }
+    else
     {
         Log(("pdmR3DevHlp_PCIPhysRead: caller='%s'/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbRead=%#zx\n",
              pDevIns->pReg->szName, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbRead));
@@ -1415,18 +1665,21 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GC
 
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnPCIPhysWrite} */
-static DECLCALLBACK(int) pdmR3DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+static DECLCALLBACK(int)
+pdmR3DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
 
 #ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
     /*
      * Just check the busmaster setting here and forward the request to the generic read helper.
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR3;
-    AssertReleaseMsg(pPciDev, ("No PCI device registered!\n"));
-
-    if (!PCIDevIsBusmaster(pPciDev))
+    if (PCIDevIsBusmaster(pPciDev))
+    { /* likely */ }
+    else
     {
         Log(("pdmR3DevHlp_PCIPhysWrite: caller='%s'/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbWrite=%#zx\n",
              pDevIns->pReg->szName, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbWrite));
@@ -1439,10 +1692,14 @@ static DECLCALLBACK(int) pdmR3DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS G
 
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnPCISetIrq} */
-static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
+static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
-    LogFlow(("pdmR3DevHlp_PCISetIrq: caller='%s'/%d: iIrq=%d iLevel=%d\n", pDevIns->pReg->szName, pDevIns->iInstance, iIrq, iLevel));
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
+    AssertReturnVoid(pPciDev);
+    LogFlow(("pdmR3DevHlp_PCISetIrq: caller='%s'/%d: pPciDev=%p:{%#x} iIrq=%d iLevel=%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iIrq, iLevel));
 
     /*
      * Validate input.
@@ -1453,77 +1710,40 @@ static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, in
     /*
      * Must have a PCI device registered!
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR3;
-    if (pPciDev)
-    {
-        PPDMPCIBUS pBus = pDevIns->Internal.s.pPciBusR3; /** @todo the bus should be associated with the PCI device not the PDM device. */
-        Assert(pBus);
-        PVM pVM = pDevIns->Internal.s.pVMR3;
+    PPDMPCIBUS pBus = pPciDev->Int.s.pPdmBusR3;
+    Assert(pBus);
+    PVM pVM = pDevIns->Internal.s.pVMR3;
 
-        pdmLock(pVM);
-        uint32_t uTagSrc;
-        if (iLevel & PDM_IRQ_LEVEL_HIGH)
-        {
-            pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing);
-            if (iLevel == PDM_IRQ_LEVEL_HIGH)
-                VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
-            else
-                VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
-        }
+    pdmLock(pVM);
+    uint32_t uTagSrc;
+    if (iLevel & PDM_IRQ_LEVEL_HIGH)
+    {
+        pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing);
+        if (iLevel == PDM_IRQ_LEVEL_HIGH)
+            VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
         else
-            uTagSrc = pDevIns->Internal.s.uLastIrqTag;
-
-        pBus->pfnSetIrqR3(pBus->pDevInsR3, pPciDev, iIrq, iLevel, uTagSrc);
-
-        if (iLevel == PDM_IRQ_LEVEL_LOW)
-            VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
-        pdmUnlock(pVM);
+            VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
     }
     else
-        AssertReleaseMsgFailed(("No PCI device registered!\n"));
+        uTagSrc = pDevIns->Internal.s.uLastIrqTag;
+
+    pBus->pfnSetIrqR3(pBus->pDevInsR3, pPciDev, iIrq, iLevel, uTagSrc);
+
+    if (iLevel == PDM_IRQ_LEVEL_LOW)
+        VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
+    pdmUnlock(pVM);
 
     LogFlow(("pdmR3DevHlp_PCISetIrq: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
 }
 
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnPCISetIrqNoWait} */
-static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel)
+static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrqNoWait(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
 {
-    pdmR3DevHlp_PCISetIrq(pDevIns, iIrq, iLevel);
+    pdmR3DevHlp_PCISetIrq(pDevIns, pPciDev, iIrq, iLevel);
 }
 
 
-/** @interface_method_impl{PDMDEVHLPR3,pfnPCIRegisterMsi} */
-static DECLCALLBACK(int) pdmR3DevHlp_PCIRegisterMsi(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg)
-{
-    PDMDEV_ASSERT_DEVINS(pDevIns);
-    LogFlow(("pdmR3DevHlp_PCIRegisterMsi: caller='%s'/%d: %d MSI vectors %d MSI-X vectors\n", pDevIns->pReg->szName, pDevIns->iInstance, pMsiReg->cMsiVectors,pMsiReg->cMsixVectors ));
-    int rc = VINF_SUCCESS;
-
-    /*
-     * Must have a PCI device registered!
-     */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR3;
-    if (pPciDev)
-    {
-        PPDMPCIBUS pBus = pDevIns->Internal.s.pPciBusR3; /** @todo the bus should be associated with the PCI device not the PDM device. */
-        Assert(pBus);
-
-        PVM pVM = pDevIns->Internal.s.pVMR3;
-        pdmLock(pVM);
-        if (pBus->pfnRegisterMsiR3)
-            rc = pBus->pfnRegisterMsiR3(pBus->pDevInsR3, pPciDev, pMsiReg);
-        else
-            rc = VERR_NOT_IMPLEMENTED;
-        pdmUnlock(pVM);
-    }
-    else
-        AssertReleaseMsgFailed(("No PCI device registered!\n"));
-
-    LogFlow(("pdmR3DevHlp_PCISetIrq: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
-    return rc;
-}
-
 /** @interface_method_impl{PDMDEVHLPR3,pfnISASetIrq} */
 static DECLCALLBACK(void) pdmR3DevHlp_ISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
 {
@@ -3620,9 +3840,10 @@ const PDMDEVHLPR3 g_pdmR3DevHlpTrusted =
     pdmR3DevHlp_MMIORegisterR0,
     pdmR3DevHlp_MMIODeregister,
     pdmR3DevHlp_MMIO2Register,
-    pdmR3DevHlp_MMIO2Deregister,
-    pdmR3DevHlp_MMIO2Map,
-    pdmR3DevHlp_MMIO2Unmap,
+    pdmR3DevHlp_MMIOExPreRegister,
+    pdmR3DevHlp_MMIOExDeregister,
+    pdmR3DevHlp_MMIOExMap,
+    pdmR3DevHlp_MMIOExUnmap,
     pdmR3DevHlp_MMHyperMapMMIO2,
     pdmR3DevHlp_MMIO2MapKernel,
     pdmR3DevHlp_ROMRegister,
@@ -3705,6 +3926,9 @@ const PDMDEVHLPR3 g_pdmR3DevHlpTrusted =
     0,
     0,
     0,
+    0,
+    0,
+    0,
     pdmR3DevHlp_GetUVM,
     pdmR3DevHlp_GetVM,
     pdmR3DevHlp_GetVMCPU,
@@ -3873,9 +4097,10 @@ const PDMDEVHLPR3 g_pdmR3DevHlpUnTrusted =
     pdmR3DevHlp_MMIORegisterR0,
     pdmR3DevHlp_MMIODeregister,
     pdmR3DevHlp_MMIO2Register,
-    pdmR3DevHlp_MMIO2Deregister,
-    pdmR3DevHlp_MMIO2Map,
-    pdmR3DevHlp_MMIO2Unmap,
+    pdmR3DevHlp_MMIOExPreRegister,
+    pdmR3DevHlp_MMIOExDeregister,
+    pdmR3DevHlp_MMIOExMap,
+    pdmR3DevHlp_MMIOExUnmap,
     pdmR3DevHlp_MMHyperMapMMIO2,
     pdmR3DevHlp_MMIO2MapKernel,
     pdmR3DevHlp_ROMRegister,
@@ -3958,6 +4183,9 @@ const PDMDEVHLPR3 g_pdmR3DevHlpUnTrusted =
     0,
     0,
     0,
+    0,
+    0,
+    0,
     pdmR3DevHlp_Untrusted_GetUVM,
     pdmR3DevHlp_Untrusted_GetVM,
     pdmR3DevHlp_Untrusted_GetVMCPU,
@@ -3995,22 +4223,21 @@ DECLCALLBACK(bool) pdmR3DevHlpQueueConsumer(PVM pVM, PPDMQUEUEITEMCORE pItem)
     switch (pTask->enmOp)
     {
         case PDMDEVHLPTASKOP_ISA_SET_IRQ:
-            PDMIsaSetIrq(pVM, pTask->u.SetIRQ.iIrq, pTask->u.SetIRQ.iLevel, pTask->u.SetIRQ.uTagSrc);
+            PDMIsaSetIrq(pVM, pTask->u.IsaSetIRQ.iIrq, pTask->u.IsaSetIRQ.iLevel, pTask->u.IsaSetIRQ.uTagSrc);
             break;
 
         case PDMDEVHLPTASKOP_PCI_SET_IRQ:
         {
             /* Same as pdmR3DevHlp_PCISetIrq, except we've got a tag already. */
-            PPDMDEVINS pDevIns = pTask->pDevInsR3;
-            PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR3;
+            PPDMPCIDEV pPciDev = pTask->u.PciSetIRQ.pPciDevR3;
             if (pPciDev)
             {
-                PPDMPCIBUS pBus = pDevIns->Internal.s.pPciBusR3; /** @todo the bus should be associated with the PCI device not the PDM device. */
+                PPDMPCIBUS pBus = pPciDev->Int.s.pPdmBusR3;
                 Assert(pBus);
 
                 pdmLock(pVM);
-                pBus->pfnSetIrqR3(pBus->pDevInsR3, pPciDev, pTask->u.SetIRQ.iIrq,
-                                  pTask->u.SetIRQ.iLevel, pTask->u.SetIRQ.uTagSrc);
+                pBus->pfnSetIrqR3(pBus->pDevInsR3, pPciDev, pTask->u.PciSetIRQ.iIrq,
+                                  pTask->u.PciSetIRQ.iLevel, pTask->u.PciSetIRQ.uTagSrc);
                 pdmUnlock(pVM);
             }
             else
@@ -4019,7 +4246,7 @@ DECLCALLBACK(bool) pdmR3DevHlpQueueConsumer(PVM pVM, PPDMQUEUEITEMCORE pItem)
         }
 
         case PDMDEVHLPTASKOP_IOAPIC_SET_IRQ:
-            PDMIoApicSetIrq(pVM, pTask->u.SetIRQ.iIrq, pTask->u.SetIRQ.iLevel, pTask->u.SetIRQ.uTagSrc);
+            PDMIoApicSetIrq(pVM, pTask->u.IoApicSetIRQ.iIrq, pTask->u.IoApicSetIRQ.iLevel, pTask->u.IoApicSetIRQ.uTagSrc);
             break;
 
         default:
diff --git a/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp b/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
index bb9e2a0..752455a 100644
--- a/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
+++ b/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
@@ -578,13 +578,13 @@ static DECLCALLBACK(void) pdmR3PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS
     PDMIoApicSendMsi(pDevIns->Internal.s.pVMR3, GCPhys, uValue, uTagSrc);
 }
 
-/** @interface_method_impl{PDMPCIHLPR3,pfnIsMMIO2Base} */
+/** @interface_method_impl{PDMPCIHLPR3,pfnIsMMIOExBase} */
 static DECLCALLBACK(bool) pdmR3PciHlp_IsMMIO2Base(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
     VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-    bool fRc = PGMR3PhysMMIO2IsBase(pDevIns->Internal.s.pVMR3, pOwner, GCPhys);
-    Log4(("pdmR3PciHlp_IsMMIO2Base: pOwner=%p GCPhys=%RGp -> %RTbool\n", pOwner, GCPhys, fRc));
+    bool fRc = PGMR3PhysMMIOExIsBase(pDevIns->Internal.s.pVMR3, pOwner, GCPhys);
+    Log4(("pdmR3PciHlp_IsMMIOExBase: pOwner=%p GCPhys=%RGp -> %RTbool\n", pOwner, GCPhys, fRc));
     return fRc;
 }
 
diff --git a/src/VBox/VMM/VMMR3/PDMDevice.cpp b/src/VBox/VMM/VMMR3/PDMDevice.cpp
index 4ea5228..f7fee1f 100644
--- a/src/VBox/VMM/VMMR3/PDMDevice.cpp
+++ b/src/VBox/VMM/VMMR3/PDMDevice.cpp
@@ -331,12 +331,9 @@ int pdmR3DevInit(PVM pVM)
         pDevIns->Internal.s.pVMRC               = pVM->pVMRC;
         //pDevIns->Internal.s.pLunsR3             = NULL;
         pDevIns->Internal.s.pCfgHandle          = paDevs[i].pNode;
-        //pDevIns->Internal.s.pPciDeviceR3        = NULL;
-        //pDevIns->Internal.s.pPciBusR3           = NULL;
-        //pDevIns->Internal.s.pPciDeviceR0        = 0;
-        //pDevIns->Internal.s.pPciBusR0           = 0;
-        //pDevIns->Internal.s.pPciDeviceRC        = 0;
-        //pDevIns->Internal.s.pPciBusRC           = 0;
+        //pDevIns->Internal.s.pHeadPciDevR3       = NULL;
+        //pDevIns->Internal.s.pHeadPciDevR0       = 0;
+        //pDevIns->Internal.s.pHeadPciDevRC       = 0;
         pDevIns->Internal.s.fIntFlags           = PDMDEVINSINT_FLAGS_SUSPENDED;
         //pDevIns->Internal.s.uLastIrqTag         = 0;
         pDevIns->pHlpR3                         = fTrusted ? &g_pdmR3DevHlpTrusted : &g_pdmR3DevHlpUnTrusted;
diff --git a/src/VBox/VMM/VMMR3/PDMDriver.cpp b/src/VBox/VMM/VMMR3/PDMDriver.cpp
index b798771..1de9e1f 100644
--- a/src/VBox/VMM/VMMR3/PDMDriver.cpp
+++ b/src/VBox/VMM/VMMR3/PDMDriver.cpp
@@ -467,6 +467,17 @@ static int pdmR3DrvMaybeTransformChain(PVM pVM, PPDMDRVINS pDrvAbove, PPDMLUN pL
         /*
          * We've got a match! Now, what are we supposed to do?
          */
+        /** @cfgm{/PDM/DriverTransformations/<name>/Action,string,inject}
+         * The action that the transformation takes.  Possible values are:
+         *      - inject
+         *      - mergeconfig: This merges and the content of the 'Config' key under the
+         *        transformation into the driver's own 'Config' key, replacing any
+         *        duplicates.
+         *      - remove
+         *      - removetree
+         *      - replace
+         *      - replacetree
+         */
         char szAction[16];
         rc = CFGMR3QueryStringDef(pCurTrans, "Action", szAction, sizeof(szAction), "inject");
         AssertLogRelRCReturn(rc, rc);
diff --git a/src/VBox/VMM/VMMR3/PGM.cpp b/src/VBox/VMM/VMMR3/PGM.cpp
index 7cc1a40..fb989ab 100644
--- a/src/VBox/VMM/VMMR3/PGM.cpp
+++ b/src/VBox/VMM/VMMR3/PGM.cpp
@@ -2375,7 +2375,7 @@ VMMR3DECL(void) PGMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
      * Update the pSelfRC pointer of the MMIO2 ram ranges since they might not
      * be mapped and thus not included in the above exercise.
      */
-    for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
+    for (PPGMREGMMIORANGE pCur = pVM->pgm.s.pRegMmioRangesR3; pCur; pCur = pCur->pNextR3)
         if (!(pCur->RamRange.fFlags & PGM_RAM_RANGE_FLAGS_FLOATING))
             pCur->RamRange.pSelfRC = MMHyperCCToRC(pVM, &pCur->RamRange);
 
diff --git a/src/VBox/VMM/VMMR3/PGMPhys.cpp b/src/VBox/VMM/VMMR3/PGMPhys.cpp
index 66f3c00..a6f090c 100644
--- a/src/VBox/VMM/VMMR3/PGMPhys.cpp
+++ b/src/VBox/VMM/VMMR3/PGMPhys.cpp
@@ -1497,9 +1497,8 @@ static void pgmR3PhysInitAndLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, RTGCPHYS GC
 
 
 /**
- * Relocate a floating RAM range.
- *
- * @copydoc FNPGMRELOCATE
+ * @callback_method_impl{FNPGMRELOCATE, Relocate a floating RAM range.}
+ * @sa pgmR3PhysMMIO2ExRangeRelocate
  */
 static DECLCALLBACK(bool) pgmR3PhysRamRangeRelocate(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew,
                                                     PGMRELOCATECALL enmMode, void *pvUser)
@@ -2442,22 +2441,491 @@ VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
  * @returns Pointer to the MMIO2 range.
  * @param   pVM             The cross context VM structure.
  * @param   pDevIns         The device instance owning the region.
+ * @param   iSubDev         The sub-device number.
  * @param   iRegion         The region.
  */
-DECLINLINE(PPGMMMIO2RANGE) pgmR3PhysMMIO2Find(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
+DECLINLINE(PPGMREGMMIORANGE) pgmR3PhysMMIOExFind(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion)
 {
     /*
-     * Search the list.
+     * Search the list.  There shouldn't be many entries.
      */
-    for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
+    /** @todo Optimize this lookup! There may now be many entries and it'll
+     *        become really slow when doing MMR3HyperMapMMIO2 and similar. */
+    for (PPGMREGMMIORANGE pCur = pVM->pgm.s.pRegMmioRangesR3; pCur; pCur = pCur->pNextR3)
         if (   pCur->pDevInsR3 == pDevIns
-            && pCur->iRegion == iRegion)
+            && pCur->iRegion == iRegion
+            && pCur->iSubDev == iSubDev)
             return pCur;
     return NULL;
 }
 
 
 /**
+ * @callback_method_impl{FNPGMRELOCATE, Relocate a floating MMIO/MMIO2 range.}
+ * @sa pgmR3PhysRamRangeRelocate
+ */
+static DECLCALLBACK(bool) pgmR3PhysMMIOExRangeRelocate(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew,
+                                                       PGMRELOCATECALL enmMode, void *pvUser)
+{
+    PPGMREGMMIORANGE pMmio = (PPGMREGMMIORANGE)pvUser;
+    Assert(pMmio->RamRange.fFlags & PGM_RAM_RANGE_FLAGS_FLOATING);
+    Assert(pMmio->RamRange.pSelfRC == GCPtrOld + PAGE_SIZE + RT_UOFFSETOF(PGMREGMMIORANGE, RamRange)); RT_NOREF_PV(GCPtrOld);
+
+    switch (enmMode)
+    {
+        case PGMRELOCATECALL_SUGGEST:
+            return true;
+
+        case PGMRELOCATECALL_RELOCATE:
+        {
+            /*
+             * Update myself, then relink all the ranges and flush the RC TLB.
+             */
+            pgmLock(pVM);
+
+            pMmio->RamRange.pSelfRC = (RTRCPTR)(GCPtrNew + PAGE_SIZE + RT_UOFFSETOF(PGMREGMMIORANGE, RamRange));
+
+            pgmR3PhysRelinkRamRanges(pVM);
+            for (unsigned i = 0; i < PGM_RAMRANGE_TLB_ENTRIES; i++)
+                pVM->pgm.s.apRamRangesTlbRC[i] = NIL_RTRCPTR;
+
+            pgmUnlock(pVM);
+            return true;
+        }
+
+        default:
+            AssertFailedReturn(false);
+    }
+}
+
+
+/**
+ * Calculates the number of chunks
+ *
+ * @returns Number of registration chunk needed.
+ * @param   pVM             The cross context VM structure.
+ * @param   cb              The size of the MMIO/MMIO2 range.
+ * @param   pcPagesPerChunk Where to return the number of pages tracked by each
+ *                          chunk.  Optional.
+ * @param   pcbChunk        Where to return the guest mapping size for a chunk.
+ */
+static uint16_t pgmR3PhysMMIOExCalcChunkCount(PVM pVM, RTGCPHYS cb, uint32_t *pcPagesPerChunk, uint32_t *pcbChunk)
+{
+    /*
+     * This is the same calculation as PGMR3PhysRegisterRam does, except we'll be
+     * needing a few bytes extra the PGMREGMMIORANGE structure.
+     *
+     * Note! In additions, we've got a 24 bit sub-page range for MMIO2 ranges, leaving
+     *       us with an absolute maximum of 16777215 pages per chunk (close to 64 GB).
+     */
+    uint32_t cbChunk;
+    uint32_t cPagesPerChunk;
+    if (HMIsEnabled(pVM))
+    {
+        cbChunk = 16U*_1M;
+        cPagesPerChunk = 1048048; /* max ~1048059 */
+        AssertCompile(sizeof(PGMREGMMIORANGE) + sizeof(PGMPAGE) * 1048048 < 16U*_1M - PAGE_SIZE * 2);
+    }
+    else
+    {
+        cbChunk = 4U*_1M;
+        cPagesPerChunk = 261616; /* max ~261627 */
+        AssertCompile(sizeof(PGMREGMMIORANGE) + sizeof(PGMPAGE) * 261616  <  4U*_1M - PAGE_SIZE * 2);
+    }
+    AssertRelease(cPagesPerChunk <= PGM_MMIO2_MAX_PAGE_COUNT); /* See above note. */
+    AssertRelease(RT_UOFFSETOF(PGMREGMMIORANGE, RamRange.aPages[cPagesPerChunk]) + PAGE_SIZE * 2 <= cbChunk);
+    if (pcbChunk)
+        *pcbChunk = cbChunk;
+    if (pcPagesPerChunk)
+        *pcPagesPerChunk = cPagesPerChunk;
+
+    /* Calc the number of chunks we need. */
+    RTGCPHYS const cPages = cb >> X86_PAGE_SHIFT;
+    uint16_t cChunks = (uint16_t)((cPages + cPagesPerChunk - 1) / cPagesPerChunk);
+    AssertRelease((RTGCPHYS)cChunks * cPagesPerChunk >= cPages);
+    return cChunks;
+}
+
+
+/**
+ * Worker for PGMR3PhysMMIOExPreRegister & PGMR3PhysMMIO2Register that allocates
+ * and the PGMREGMMIORANGE structures and does basic initialization.
+ *
+ * Caller must set type specfic members and initialize the PGMPAGE structures.
+ *
+ * @returns VBox status code.
+ * @param   pVM             The cross context VM structure.
+ * @param   pDevIns         The device instance owning the region.
+ * @param   iSubDev         The sub-device number (internal PCI config number).
+ * @param   iRegion         The region number.  If the MMIO2 memory is a PCI
+ *                          I/O region this number has to be the number of that
+ *                          region. Otherwise it can be any number safe
+ *                          UINT8_MAX.
+ * @param   cb              The size of the region.  Must be page aligned.
+ * @param   pszDesc         The description.
+ * @param   ppHeadRet       Where to return the pointer to the first
+ *                          registration chunk.
+ *
+ * @thread  EMT
+ */
+static int pgmR3PhysMMIOExCreate(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb,
+                                 const char *pszDesc, PPGMREGMMIORANGE *ppHeadRet)
+{
+    /*
+     * Figure out how many chunks we need and of which size.
+     */
+    uint32_t cPagesPerChunk;
+    uint16_t cChunks = pgmR3PhysMMIOExCalcChunkCount(pVM, cb, &cPagesPerChunk, NULL);
+    AssertReturn(cChunks, VERR_PGM_PHYS_MMIO_EX_IPE);
+
+    /*
+     * Allocate the chunks.
+     */
+    PPGMREGMMIORANGE *ppNext = ppHeadRet;
+    *ppNext = NULL;
+
+    int rc = VINF_SUCCESS;
+    uint32_t cPagesLeft = cb >> X86_PAGE_SHIFT;
+    for (uint16_t iChunk = 0; iChunk < cChunks && RT_SUCCESS(rc); iChunk++)
+    {
+        /*
+         * We currently do a single RAM range for the whole thing.  This will
+         * probably have to change once someone needs really large MMIO regions,
+         * as we will be running into SUPR3PageAllocEx limitations and such.
+         */
+        const uint32_t   cPagesTrackedByChunk = RT_MIN(cPagesLeft, cPagesPerChunk);
+        const size_t     cbRange = RT_OFFSETOF(PGMREGMMIORANGE, RamRange.aPages[cPagesTrackedByChunk]);
+        PPGMREGMMIORANGE pNew    = NULL;
+        if (   cPagesTrackedByChunk > cPagesLeft
+            || cbRange >= _1M)
+        {
+            /*
+             * Allocate memory for the registration structure.
+             */
+            size_t const cChunkPages  = RT_ALIGN_Z(cbRange, PAGE_SIZE) >> PAGE_SHIFT;
+            size_t const cbChunk      = (1 + cChunkPages + 1) << PAGE_SHIFT;
+            AssertLogRelBreakStmt(cbChunk == (uint32_t)cbChunk, rc = VERR_OUT_OF_RANGE);
+            PSUPPAGE     paChunkPages = (PSUPPAGE)RTMemTmpAllocZ(sizeof(SUPPAGE) * cChunkPages);
+            AssertBreakStmt(paChunkPages, rc = VERR_NO_TMP_MEMORY);
+            RTR0PTR      R0PtrChunk   = NIL_RTR0PTR;
+            void        *pvChunk      = NULL;
+            rc = SUPR3PageAllocEx(cChunkPages, 0 /*fFlags*/, &pvChunk,
+#if defined(VBOX_WITH_MORE_RING0_MEM_MAPPINGS)
+                                  &R0PtrChunk,
+#elif defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
+                                  HMIsEnabled(pVM) ? &R0PtrChunk : NULL,
+#else
+                                  NULL,
+#endif
+                                  paChunkPages);
+            AssertLogRelMsgRCBreakStmt(rc, ("rc=%Rrc, cChunkPages=%#zx\n", rc, cChunkPages), RTMemTmpFree(paChunkPages));
+
+#if defined(VBOX_WITH_MORE_RING0_MEM_MAPPINGS)
+            Assert(R0PtrChunk != NIL_RTR0PTR);
+#elif defined(VBOX_WITH_2X_4GB_ADDR_SPACE)
+            if (!HMIsEnabled(pVM))
+                R0PtrChunk = NIL_RTR0PTR;
+#else
+            R0PtrChunk = (uintptr_t)pvChunk;
+#endif
+            memset(pvChunk, 0, cChunkPages << PAGE_SHIFT);
+
+            pNew = (PPGMREGMMIORANGE)pvChunk;
+            pNew->RamRange.fFlags   = PGM_RAM_RANGE_FLAGS_FLOATING;
+            pNew->RamRange.pSelfR0  = R0PtrChunk + RT_OFFSETOF(PGMREGMMIORANGE, RamRange);
+
+            /*
+             * If we might end up in raw-mode, make a HMA mapping of the range,
+             * just like we do for memory above 4GB.
+             */
+            if (HMIsEnabled(pVM))
+                pNew->RamRange.pSelfRC  = NIL_RTRCPTR;
+            else
+            {
+                RTGCPTR         GCPtrChunkMap = pVM->pgm.s.GCPtrPrevRamRangeMapping - cbChunk;
+                RTGCPTR const   GCPtrChunk    = GCPtrChunkMap + PAGE_SIZE;
+                rc = PGMR3MapPT(pVM, GCPtrChunkMap, (uint32_t)cbChunk, 0 /*fFlags*/, pgmR3PhysMMIOExRangeRelocate, pNew, pszDesc);
+                if (RT_SUCCESS(rc))
+                {
+                    pVM->pgm.s.GCPtrPrevRamRangeMapping = GCPtrChunkMap;
+
+                    RTGCPTR GCPtrPage  = GCPtrChunk;
+                    for (uint32_t iPage = 0; iPage < cPagesTrackedByChunk && RT_SUCCESS(rc); iPage++, GCPtrPage += PAGE_SIZE)
+                        rc = PGMMap(pVM, GCPtrPage, paChunkPages[iPage].Phys, PAGE_SIZE, 0);
+                }
+                if (RT_FAILURE(rc))
+                {
+                    SUPR3PageFreeEx(pvChunk, cChunkPages);
+                    break;
+                }
+                pNew->RamRange.pSelfRC  = GCPtrChunk + RT_OFFSETOF(PGMREGMMIORANGE, RamRange);
+            }
+        }
+        /*
+         * Not so big, do a one time hyper allocation.
+         */
+        else
+        {
+            rc = MMR3HyperAllocOnceNoRel(pVM, cbRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
+            AssertLogRelMsgRCBreak(rc, ("cbRange=%zu\n", cbRange));
+
+            /*
+             * Initialize allocation specific items.
+             */
+            //pNew->RamRange.fFlags = 0;
+            pNew->RamRange.pSelfR0  = MMHyperCCToR0(pVM, &pNew->RamRange);
+            pNew->RamRange.pSelfRC  = MMHyperCCToRC(pVM, &pNew->RamRange);
+        }
+
+        /*
+         * Initialize the registration structure (caller does specific bits).
+         */
+        pNew->pDevInsR3             = pDevIns;
+        //pNew->pvR3                = NULL;
+        //pNew->pNext               = NULL;
+        //pNew->fFlags              = 0;
+        if (iChunk == 0)
+            pNew->fFlags |= PGMREGMMIORANGE_F_FIRST_CHUNK;
+        if (iChunk + 1 == cChunks)
+            pNew->fFlags |= PGMREGMMIORANGE_F_LAST_CHUNK;
+        pNew->iSubDev               = iSubDev;
+        pNew->iRegion               = iRegion;
+        pNew->idSavedState          = UINT8_MAX;
+        pNew->idMmio2               = UINT8_MAX;
+        //pNew->pPhysHandlerR3      = NULL;
+        //pNew->paLSPages           = NULL;
+        pNew->RamRange.GCPhys       = NIL_RTGCPHYS;
+        pNew->RamRange.GCPhysLast   = NIL_RTGCPHYS;
+        pNew->RamRange.pszDesc      = pszDesc;
+        pNew->RamRange.cb           = (RTGCPHYS)cPagesTrackedByChunk << X86_PAGE_SHIFT;
+        pNew->RamRange.fFlags      |= PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO_EX;
+        //pNew->RamRange.pvR3       = NULL;
+        //pNew->RamRange.paLSPages  = NULL;
+
+        *ppNext = pNew;
+        ASMCompilerBarrier();
+        ppNext = &pNew->pNextR3;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        Assert((*ppHeadRet)->fFlags & PGMREGMMIORANGE_F_FIRST_CHUNK);
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * Free floating ranges.
+     */
+    while (*ppHeadRet)
+    {
+        PPGMREGMMIORANGE pFree = *ppHeadRet;
+        *ppHeadRet = pFree->pNextR3;
+
+        if (pFree->RamRange.fFlags & PGM_RAM_RANGE_FLAGS_FLOATING)
+        {
+            const size_t    cbRange     = RT_OFFSETOF(PGMREGMMIORANGE, RamRange.aPages[pFree->RamRange.cb >> X86_PAGE_SHIFT]);
+            size_t const    cChunkPages = RT_ALIGN_Z(cbRange, PAGE_SIZE) >> PAGE_SHIFT;
+            SUPR3PageFreeEx(pFree, cChunkPages);
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * Common worker PGMR3PhysMMIOExPreRegister & PGMR3PhysMMIO2Register that links
+ * a complete registration entry into the lists and lookup tables.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pNew            The new MMIO / MMIO2 registration to link.
+ */
+static void pgmR3PhysMMIOExLink(PVM pVM, PPGMREGMMIORANGE pNew)
+{
+    /*
+     * Link it into the list (order doesn't matter, so insert it at the head).
+     *
+     * Note! The range we're link may consist of multiple chunks, so we have to
+     *       find the last one.
+     */
+    PPGMREGMMIORANGE pLast = pNew;
+    for (pLast = pNew; ; pLast = pLast->pNextR3)
+    {
+        if (pLast->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+            break;
+        Assert(pLast->pNextR3);
+        Assert(pLast->pNextR3->pDevInsR3 == pNew->pDevInsR3);
+        Assert(pLast->pNextR3->iSubDev   == pNew->iSubDev);
+        Assert(pLast->pNextR3->iRegion   == pNew->iRegion);
+        Assert((pLast->pNextR3->fFlags & PGMREGMMIORANGE_F_MMIO2) == (pNew->fFlags & PGMREGMMIORANGE_F_MMIO2));
+        Assert(pLast->pNextR3->idMmio2   == (pLast->fFlags & PGMREGMMIORANGE_F_MMIO2 ? pNew->idMmio2 + 1 : UINT8_MAX));
+    }
+
+    pgmLock(pVM);
+
+    /* Link in the chain of ranges at the head of the list. */
+    pLast->pNextR3 = pVM->pgm.s.pRegMmioRangesR3;
+    pVM->pgm.s.pRegMmioRangesR3 = pNew;
+
+    /* If MMIO, insert the MMIO2 range/page IDs. */
+    uint8_t idMmio2 = pNew->idMmio2;
+    if (idMmio2 != UINT8_MAX)
+    {
+        for (;;)
+        {
+            Assert(pNew->fFlags & PGMREGMMIORANGE_F_MMIO2);
+            Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] == NULL);
+            Assert(pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] == NIL_RTR0PTR);
+            pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] = pNew;
+            pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] = pNew->RamRange.pSelfR0 - RT_OFFSETOF(PGMREGMMIORANGE, RamRange);
+            if (pNew->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+                break;
+            pNew = pNew->pNextR3;
+        }
+    }
+    else
+        Assert(!(pNew->fFlags & PGMREGMMIORANGE_F_MMIO2));
+
+    pgmPhysInvalidatePageMapTLB(pVM);
+    pgmUnlock(pVM);
+}
+
+
+/**
+ * Allocate and pre-register an MMIO region.
+ *
+ * This is currently the way to deal with large MMIO regions.  It may in the
+ * future be extended to be the way we deal with all MMIO regions, but that
+ * means we'll have to do something about the simple list based approach we take
+ * to tracking the registrations.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS on success, *ppv pointing to the R3 mapping of the
+ *          memory.
+ * @retval  VERR_ALREADY_EXISTS if the region already exists.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pDevIns         The device instance owning the region.
+ * @param   iSubDev         The sub-device number.
+ * @param   iRegion         The region number.  If the MMIO2 memory is a PCI
+ *                          I/O region this number has to be the number of that
+ *                          region. Otherwise it can be any number safe
+ *                          UINT8_MAX.
+ * @param   cbRegion        The size of the region.  Must be page aligned.
+ * @param   hType           The physical handler callback type.
+ * @param   pvUserR3        User parameter for ring-3 context callbacks.
+ * @param   pvUserR0        User parameter for ring-0 context callbacks.
+ * @param   pvUserRC        User parameter for raw-mode context callbacks.
+ * @param   pszDesc         The description.
+ *
+ * @thread  EMT
+ *
+ * @sa      PGMR3PhysMMIORegister, PGMR3PhysMMIO2Register,
+ *          PGMR3PhysMMIOExMap, PGMR3PhysMMIOExUnmap, PGMR3PhysMMIOExDeregister.
+ */
+VMMR3DECL(int) PGMR3PhysMMIOExPreRegister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRegion,
+                                          PGMPHYSHANDLERTYPE hType, RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC,
+                                          const char *pszDesc)
+{
+    /*
+     * Validate input.
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
+    AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
+    AssertReturn(pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion) == NULL, VERR_ALREADY_EXISTS);
+    AssertReturn(!(cbRegion & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+    AssertReturn(cbRegion, VERR_INVALID_PARAMETER);
+
+    const uint32_t cPages = cbRegion >> PAGE_SHIFT;
+    AssertLogRelReturn(((RTGCPHYS)cPages << PAGE_SHIFT) == cbRegion, VERR_INVALID_PARAMETER);
+    AssertLogRelReturn(cPages <= (MM_MMIO_64_MAX >> X86_PAGE_SHIFT), VERR_OUT_OF_RANGE);
+
+    /*
+     * For the 2nd+ instance, mangle the description string so it's unique.
+     */
+    if (pDevIns->iInstance > 0) /** @todo Move to PDMDevHlp.cpp and use a real string cache. */
+    {
+        pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s [%u]", pszDesc, pDevIns->iInstance);
+        if (!pszDesc)
+            return VERR_NO_MEMORY;
+    }
+
+    /*
+     * Register the MMIO callbacks.
+     */
+    PPGMPHYSHANDLER pPhysHandler;
+    int rc = pgmHandlerPhysicalExCreate(pVM, hType, pvUserR3, pvUserR0, pvUserRC, pszDesc, &pPhysHandler);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Create the registered MMIO range record for it.
+         */
+        PPGMREGMMIORANGE pNew;
+        rc = pgmR3PhysMMIOExCreate(pVM, pDevIns, iSubDev, iRegion, cbRegion, pszDesc, &pNew);
+        if (RT_SUCCESS(rc))
+        {
+            Assert(!(pNew->fFlags & PGMREGMMIORANGE_F_MMIO2));
+
+            /*
+             * Intialize the page structures and set up physical handlers (one for each chunk).
+             */
+            for (PPGMREGMMIORANGE pCur = pNew; pCur != NULL && RT_SUCCESS(rc); pCur = pCur->pNextR3)
+            {
+                if (pCur == pNew)
+                    pCur->pPhysHandlerR3 = pPhysHandler;
+                else
+                    rc = pgmHandlerPhysicalExDup(pVM, pPhysHandler, &pCur->pPhysHandlerR3);
+
+                uint32_t iPage = pCur->RamRange.cb >> X86_PAGE_SHIFT;
+                while (iPage-- > 0)
+                    PGM_PAGE_INIT_ZERO(&pCur->RamRange.aPages[iPage], pVM, PGMPAGETYPE_MMIO);
+            }
+            if (RT_SUCCESS(rc))
+            {
+                /*
+                 * Update the page count stats, link the registration and we're done.
+                 */
+                pVM->pgm.s.cAllPages += cPages;
+                pVM->pgm.s.cPureMmioPages += cPages;
+
+                pgmR3PhysMMIOExLink(pVM, pNew);
+                return VINF_SUCCESS;
+            }
+
+            /*
+             * Clean up in case we're out of memory for extra access handlers.
+             */
+            while (pNew != NULL)
+            {
+                PPGMREGMMIORANGE pFree = pNew;
+                pNew = pFree->pNextR3;
+
+                if (pFree->pPhysHandlerR3)
+                {
+                    pgmHandlerPhysicalExDestroy(pVM, pFree->pPhysHandlerR3);
+                    pFree->pPhysHandlerR3 = NULL;
+                }
+
+                if (pFree->RamRange.fFlags & PGM_RAM_RANGE_FLAGS_FLOATING)
+                {
+                    const size_t    cbRange     = RT_OFFSETOF(PGMREGMMIORANGE, RamRange.aPages[pFree->RamRange.cb >> X86_PAGE_SHIFT]);
+                    size_t const    cChunkPages = RT_ALIGN_Z(cbRange, PAGE_SIZE) >> PAGE_SHIFT;
+                    SUPR3PageFreeEx(pFree, cChunkPages);
+                }
+            }
+        }
+        else
+            pgmHandlerPhysicalExDestroy(pVM, pPhysHandler);
+    }
+    return rc;
+}
+
+
+/**
  * Allocate and register an MMIO2 region.
  *
  * As mentioned elsewhere, MMIO2 is just RAM spelled differently.  It's RAM
@@ -2477,6 +2945,7 @@ DECLINLINE(PPGMMMIO2RANGE) pgmR3PhysMMIO2Find(PVM pVM, PPDMDEVINS pDevIns, uint3
  *
  * @param   pVM             The cross context VM structure.
  * @param   pDevIns         The device instance owning the region.
+ * @param   iSubDev         The sub-device number.
  * @param   iRegion         The region number.  If the MMIO2 memory is a PCI
  *                          I/O region this number has to be the number of that
  *                          region. Otherwise it can be any number safe
@@ -2486,27 +2955,29 @@ DECLINLINE(PPGMMMIO2RANGE) pgmR3PhysMMIO2Find(PVM pVM, PPDMDEVINS pDevIns, uint3
  * @param   ppv             Where to store the pointer to the ring-3 mapping of
  *                          the memory.
  * @param   pszDesc         The description.
+ * @thread  EMT
  */
-VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags,
-                                      void **ppv, const char *pszDesc)
+VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb,
+                                      uint32_t fFlags, void **ppv, const char *pszDesc)
 {
     /*
      * Validate input.
      */
     VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
     AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertPtrReturn(ppv, VERR_INVALID_POINTER);
     AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
     AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
-    AssertReturn(pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion) == NULL, VERR_ALREADY_EXISTS);
+    AssertReturn(pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion) == NULL, VERR_ALREADY_EXISTS);
     AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
     AssertReturn(cb, VERR_INVALID_PARAMETER);
     AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
 
     const uint32_t cPages = cb >> PAGE_SHIFT;
     AssertLogRelReturn(((RTGCPHYS)cPages << PAGE_SHIFT) == cb, VERR_INVALID_PARAMETER);
-    AssertLogRelReturn(cPages <= PGM_MMIO2_MAX_PAGE_COUNT, VERR_NO_MEMORY);
+    AssertLogRelReturn(cPages <= (MM_MMIO_64_MAX >> X86_PAGE_SHIFT), VERR_OUT_OF_RANGE);
 
     /*
      * For the 2nd+ instance, mangle the description string so it's unique.
@@ -2520,16 +2991,20 @@ VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iReg
 
     /*
      * Allocate an MMIO2 range ID (not freed on failure).
-     * The zero ID is not used as it could be confused with NIL_GMM_PAGEID.
+     *
+     * The zero ID is not used as it could be confused with NIL_GMM_PAGEID, so
+     * the IDs goes from 1 thru PGM_MMIO2_MAX_RANGES.
      */
+    unsigned cChunks = pgmR3PhysMMIOExCalcChunkCount(pVM, cb, NULL, NULL);
     pgmLock(pVM);
-    uint8_t idMmio2 = pVM->pgm.s.cMmio2Regions + 1;
-    if (idMmio2 > PGM_MMIO2_MAX_RANGES)
+    uint8_t  idMmio2 = pVM->pgm.s.cMmio2Regions + 1;
+    unsigned cNewMmio2Regions = pVM->pgm.s.cMmio2Regions + cChunks;
+    if (cNewMmio2Regions > PGM_MMIO2_MAX_RANGES)
     {
         pgmUnlock(pVM);
         AssertLogRelFailedReturn(VERR_PGM_TOO_MANY_MMIO2_RANGES);
     }
-    pVM->pgm.s.cMmio2Regions = idMmio2;
+    pVM->pgm.s.cMmio2Regions = cNewMmio2Regions;
     pgmUnlock(pVM);
 
     /*
@@ -2549,62 +3024,47 @@ VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iReg
                 memset(pvPages, 0, cPages * PAGE_SIZE);
 
                 /*
-                 * Create the MMIO2 range record for it.
+                 * Create the registered MMIO range record for it.
                  */
-                const size_t cbRange = RT_OFFSETOF(PGMMMIO2RANGE, RamRange.aPages[cPages]);
-                PPGMMMIO2RANGE pNew;
-                rc = MMR3HyperAllocOnceNoRel(pVM, cbRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
-                AssertLogRelMsgRC(rc, ("cbRamRange=%zu\n", cbRange));
+                PPGMREGMMIORANGE pNew;
+                rc = pgmR3PhysMMIOExCreate(pVM, pDevIns, iSubDev, iRegion, cb, pszDesc, &pNew);
                 if (RT_SUCCESS(rc))
                 {
-                    pNew->pDevInsR3             = pDevIns;
-                    pNew->pvR3                  = pvPages;
-                    //pNew->pNext               = NULL;
-                    //pNew->fMapped             = false;
-                    //pNew->fOverlapping        = false;
-                    pNew->iRegion               = iRegion;
-                    pNew->idSavedState          = UINT8_MAX;
-                    pNew->idMmio2               = idMmio2;
-                    pNew->RamRange.pSelfR0      = MMHyperCCToR0(pVM, &pNew->RamRange);
-                    pNew->RamRange.pSelfRC      = MMHyperCCToRC(pVM, &pNew->RamRange);
-                    pNew->RamRange.GCPhys       = NIL_RTGCPHYS;
-                    pNew->RamRange.GCPhysLast   = NIL_RTGCPHYS;
-                    pNew->RamRange.pszDesc      = pszDesc;
-                    pNew->RamRange.cb           = cb;
-                    pNew->RamRange.fFlags       = PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO2;
-                    pNew->RamRange.pvR3         = pvPages;
-                    //pNew->RamRange.paLSPages    = NULL;
-
-                    uint32_t iPage = cPages;
-                    while (iPage-- > 0)
+                    uint32_t iSrcPage   = 0;
+                    uint8_t *pbCurPages = (uint8_t *)pvPages;
+                    for (PPGMREGMMIORANGE pCur = pNew; pCur; pCur = pCur->pNextR3)
                     {
-                        PGM_PAGE_INIT(&pNew->RamRange.aPages[iPage],
-                                      paPages[iPage].Phys,
-                                      PGM_MMIO2_PAGEID_MAKE(idMmio2, iPage),
-                                      PGMPAGETYPE_MMIO2, PGM_PAGE_STATE_ALLOCATED);
+                        pCur->pvR3          = pbCurPages;
+                        pCur->RamRange.pvR3 = pbCurPages;
+                        pCur->idMmio2       = idMmio2;
+                        pCur->fFlags       |= PGMREGMMIORANGE_F_MMIO2;
+
+                        uint32_t iDstPage = pCur->RamRange.cb >> X86_PAGE_SHIFT;
+                        while (iDstPage-- > 0)
+                        {
+                            PGM_PAGE_INIT(&pNew->RamRange.aPages[iDstPage],
+                                          paPages[iDstPage + iSrcPage].Phys,
+                                          PGM_MMIO2_PAGEID_MAKE(idMmio2, iDstPage),
+                                          PGMPAGETYPE_MMIO2, PGM_PAGE_STATE_ALLOCATED);
+                        }
+
+                        /* advance. */
+                        iSrcPage   += pCur->RamRange.cb >> X86_PAGE_SHIFT;
+                        pbCurPages += pCur->RamRange.cb;
+                        idMmio2++;
                     }
 
-                    /* update page count stats */
-                    pVM->pgm.s.cAllPages     += cPages;
-                    pVM->pgm.s.cPrivatePages += cPages;
+                    RTMemTmpFree(paPages);
 
                     /*
-                     * Link it into the list.
-                     * Since there is no particular order, just push it.
+                     * Update the page count stats, link the registration and we're done.
                      */
-                    /** @todo we can save us the linked list now, just search the lookup table... */
-                    pgmLock(pVM);
-                    Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] == NULL);
-                    Assert(pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] == NIL_RTR0PTR);
-                    pNew->pNextR3 = pVM->pgm.s.pMmio2RangesR3;
-                    pVM->pgm.s.pMmio2RangesR3 = pNew;
-                    pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] = pNew;
-                    pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] = MMHyperCCToR0(pVM, pNew);
-                    pgmUnlock(pVM);
+                    pVM->pgm.s.cAllPages += cPages;
+                    pVM->pgm.s.cPrivatePages += cPages;
+
+                    pgmR3PhysMMIOExLink(pVM, pNew);
 
                     *ppv = pvPages;
-                    RTMemTmpFree(paPages);
-                    pgmPhysInvalidatePageMapTLB(pVM);
                     return VINF_SUCCESS;
                 }
 
@@ -2621,7 +3081,7 @@ VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iReg
 
 
 /**
- * Deregisters and frees an MMIO2 region.
+ * Deregisters and frees an MMIO2 region or a pre-registered MMIO region
  *
  * Any physical (and virtual) access handlers registered for the region must
  * be deregistered before calling this function.
@@ -2629,69 +3089,90 @@ VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iReg
  * @returns VBox status code.
  * @param   pVM             The cross context VM structure.
  * @param   pDevIns         The device instance owning the region.
- * @param   iRegion         The region. If it's UINT32_MAX it'll be a wildcard match.
+ * @param   iSubDev         The sub-device number.  Pass UINT32_MAX for wildcard
+ *                          matching.
+ * @param   iRegion         The region.  Pass UINT32_MAX for wildcard matching.
  */
-VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
+VMMR3DECL(int) PGMR3PhysMMIOExDeregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion)
 {
     /*
      * Validate input.
      */
     VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
     AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX || iSubDev == UINT32_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(iRegion <= UINT8_MAX || iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
 
+    /*
+     * The loop here scanning all registrations will make sure that multi-chunk ranges
+     * get properly deregistered, though it's original purpose was the wildcard iRegion.
+     */
     pgmLock(pVM);
     int rc = VINF_SUCCESS;
     unsigned cFound = 0;
-    PPGMMMIO2RANGE pPrev = NULL;
-    PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3;
+    PPGMREGMMIORANGE pPrev = NULL;
+    PPGMREGMMIORANGE pCur = pVM->pgm.s.pRegMmioRangesR3;
     while (pCur)
     {
         if (    pCur->pDevInsR3 == pDevIns
             &&  (   iRegion == UINT32_MAX
-                 || pCur->iRegion == iRegion))
+                 || pCur->iRegion == iRegion)
+            &&  (   iSubDev == UINT32_MAX
+                 || pCur->iSubDev == iSubDev) )
         {
             cFound++;
 
             /*
              * Unmap it if it's mapped.
              */
-            if (pCur->fMapped)
+            if (pCur->fFlags & PGMREGMMIORANGE_F_MAPPED)
             {
-                int rc2 = PGMR3PhysMMIO2Unmap(pVM, pCur->pDevInsR3, pCur->iRegion, pCur->RamRange.GCPhys);
+                int rc2 = PGMR3PhysMMIOExUnmap(pVM, pCur->pDevInsR3, pCur->iSubDev, pCur->iRegion, pCur->RamRange.GCPhys);
                 AssertRC(rc2);
                 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
                     rc = rc2;
             }
 
             /*
+             * Must tell IOM about MMIO (first one only).
+             */
+            if ((pCur->fFlags & (PGMREGMMIORANGE_F_MMIO2 | PGMREGMMIORANGE_F_FIRST_CHUNK)) == PGMREGMMIORANGE_F_MMIO2)
+                IOMR3MmioExNotifyDeregistered(pVM, pCur->pPhysHandlerR3->pvUserR3);
+
+            /*
              * Unlink it
              */
-            PPGMMMIO2RANGE pNext = pCur->pNextR3;
+            PPGMREGMMIORANGE pNext = pCur->pNextR3;
             if (pPrev)
                 pPrev->pNextR3 = pNext;
             else
-                pVM->pgm.s.pMmio2RangesR3 = pNext;
+                pVM->pgm.s.pRegMmioRangesR3 = pNext;
             pCur->pNextR3 = NULL;
 
             uint8_t idMmio2 = pCur->idMmio2;
-            Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] == pCur);
-            pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] = NULL;
-            pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] = NIL_RTR0PTR;
+            if (idMmio2 != UINT8_MAX)
+            {
+                Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] == pCur);
+                pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] = NULL;
+                pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] = NIL_RTR0PTR;
+            }
 
             /*
              * Free the memory.
              */
-            int rc2 = SUPR3PageFreeEx(pCur->pvR3, pCur->RamRange.cb >> PAGE_SHIFT);
-            AssertRC(rc2);
-            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
-                rc = rc2;
-
             uint32_t const cPages = pCur->RamRange.cb >> PAGE_SHIFT;
-            rc2 = MMR3AdjustFixedReservation(pVM, -(int32_t)cPages, pCur->RamRange.pszDesc);
-            AssertRC(rc2);
-            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
-                rc = rc2;
+            if (pCur->fFlags & PGMREGMMIORANGE_F_MMIO2)
+            {
+                int rc2 = SUPR3PageFreeEx(pCur->pvR3, cPages);
+                AssertRC(rc2);
+                if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                    rc = rc2;
+
+                rc2 = MMR3AdjustFixedReservation(pVM, -(int32_t)cPages, pCur->RamRange.pszDesc);
+                AssertRC(rc2);
+                if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                    rc = rc2;
+            }
 
             /* we're leaking hyper memory here if done at runtime. */
 #ifdef VBOX_STRICT
@@ -2705,13 +3186,27 @@ VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iR
                       || enmState == VMSTATE_CREATING
                       , ("%s\n", VMR3GetStateName(enmState)));
 #endif
-            /*rc = MMHyperFree(pVM, pCur);
-            AssertRCReturn(rc, rc); - not safe, see the alloc call. */
+
+            const bool fIsMmio2 = RT_BOOL(pCur->fFlags & PGMREGMMIORANGE_F_MMIO2);
+            if (pCur->RamRange.fFlags & PGM_RAM_RANGE_FLAGS_FLOATING)
+            {
+                const size_t    cbRange     = RT_OFFSETOF(PGMREGMMIORANGE, RamRange.aPages[cPages]);
+                size_t const    cChunkPages = RT_ALIGN_Z(cbRange, PAGE_SIZE) >> PAGE_SHIFT;
+                SUPR3PageFreeEx(pCur, cChunkPages);
+            }
+            /*else
+            {
+                rc = MMHyperFree(pVM, pCur); - does not work, see the alloc call.
+                AssertRCReturn(rc, rc);
+            } */
 
 
             /* update page count stats */
-            pVM->pgm.s.cAllPages     -= cPages;
-            pVM->pgm.s.cPrivatePages -= cPages;
+            pVM->pgm.s.cAllPages -= cPages;
+            if (fIsMmio2)
+                pVM->pgm.s.cPrivatePages -= cPages;
+            else
+                pVM->pgm.s.cPureMmioPages -= cPages;
 
             /* next */
             pCur = pNext;
@@ -2724,12 +3219,12 @@ VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iR
     }
     pgmPhysInvalidatePageMapTLB(pVM);
     pgmUnlock(pVM);
-    return !cFound && iRegion != UINT32_MAX ? VERR_NOT_FOUND : rc;
+    return !cFound && iRegion != UINT32_MAX && iSubDev != UINT32_MAX ? VERR_NOT_FOUND : rc;
 }
 
 
 /**
- * Maps a MMIO2 region.
+ * Maps a MMIO2 region or a pre-registered MMIO region.
  *
  * This is done when a guest / the bios / state loading changes the
  * PCI config. The replacing of base memory has the same restrictions
@@ -2739,34 +3234,58 @@ VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iR
  *
  * @param   pVM             The cross context VM structure.
  * @param   pDevIns         The device instance owning the region.
+ * @param   iSubDev         The sub-device number of the registered region.
  * @param   iRegion         The index of the registered region.
  * @param   GCPhys          The guest-physical address to be remapped.
  */
-VMMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+VMMR3DECL(int) PGMR3PhysMMIOExMap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS GCPhys)
 {
     /*
-     * Validate input
+     * Validate input.
+     *
+     * Note! It's safe to walk the MMIO/MMIO2 list since registrations only
+     *       happens during VM construction.
      */
     VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
     AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
     AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
     AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
 
-    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
-    AssertReturn(pCur, VERR_NOT_FOUND);
-    AssertReturn(!pCur->fMapped, VERR_WRONG_ORDER);
-    Assert(pCur->RamRange.GCPhys == NIL_RTGCPHYS);
-    Assert(pCur->RamRange.GCPhysLast == NIL_RTGCPHYS);
+    PPGMREGMMIORANGE pFirstMmio = pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion);
+    AssertReturn(pFirstMmio, VERR_NOT_FOUND);
+    Assert(pFirstMmio->fFlags & PGMREGMMIORANGE_F_FIRST_CHUNK);
 
-    const RTGCPHYS GCPhysLast = GCPhys + pCur->RamRange.cb - 1;
-    AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
+    PPGMREGMMIORANGE pLastMmio = pFirstMmio;
+    RTGCPHYS         cbRange   = 0;
+    for (;;)
+    {
+        AssertReturn(!(pLastMmio->fFlags & PGMREGMMIORANGE_F_MAPPED), VERR_WRONG_ORDER);
+        Assert(pLastMmio->RamRange.GCPhys == NIL_RTGCPHYS);
+        Assert(pLastMmio->RamRange.GCPhysLast == NIL_RTGCPHYS);
+        Assert(pLastMmio->pDevInsR3 == pFirstMmio->pDevInsR3);
+        Assert(pLastMmio->iSubDev   == pFirstMmio->iSubDev);
+        Assert(pLastMmio->iRegion   == pFirstMmio->iRegion);
+        cbRange += pLastMmio->RamRange.cb;
+        if (pLastMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+            break;
+        pLastMmio = pLastMmio->pNextR3;
+    }
+
+    RTGCPHYS GCPhysLast = GCPhys + cbRange - 1;
+    AssertLogRelReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
 
     /*
-     * Find our location in the ram range list, checking for
-     * restriction we don't bother implementing yet (partially overlapping).
+     * Find our location in the ram range list, checking for restriction
+     * we don't bother implementing yet (partially overlapping, multiple
+     * ram ranges).
      */
+    pgmLock(pVM);
+
+    AssertReturnStmt(!(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MAPPED), pgmUnlock(pVM), VERR_WRONG_ORDER);
+
     bool fRamExists = false;
     PPGMRAMRANGE pRamPrev = NULL;
     PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
@@ -2775,13 +3294,35 @@ VMMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
         if (    GCPhys     <= pRam->GCPhysLast
             &&  GCPhysLast >= pRam->GCPhys)
         {
-            /* completely within? */
-            AssertLogRelMsgReturn(   GCPhys     >= pRam->GCPhys
-                                  && GCPhysLast <= pRam->GCPhysLast,
-                                  ("%RGp-%RGp (MMIO2/%s) falls partly outside %RGp-%RGp (%s)\n",
-                                   GCPhys, GCPhysLast, pCur->RamRange.pszDesc,
-                                   pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
-                                  VERR_PGM_RAM_CONFLICT);
+            /* Completely within? */
+            AssertLogRelMsgReturnStmt(   GCPhys     >= pRam->GCPhys
+                                      && GCPhysLast <= pRam->GCPhysLast,
+                                      ("%RGp-%RGp (MMIOEx/%s) falls partly outside %RGp-%RGp (%s)\n",
+                                       GCPhys, GCPhysLast, pFirstMmio->RamRange.pszDesc,
+                                       pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
+                                      pgmUnlock(pVM),
+                                      VERR_PGM_RAM_CONFLICT);
+
+            /* Check that all the pages are RAM pages. */
+            PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
+            uint32_t cPagesLeft = cbRange >> PAGE_SHIFT;
+            while (cPagesLeft-- > 0)
+            {
+                AssertLogRelMsgReturnStmt(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
+                                          ("%RGp isn't a RAM page (%d) - mapping %RGp-%RGp (MMIO2/%s).\n",
+                                           GCPhys, PGM_PAGE_GET_TYPE(pPage), GCPhys, GCPhysLast, pFirstMmio->RamRange.pszDesc),
+                                          pgmUnlock(pVM),
+                                          VERR_PGM_RAM_CONFLICT);
+                pPage++;
+            }
+
+            /* There can only be one MMIO/MMIO2 chunk matching here! */
+            AssertLogRelMsgReturnStmt(pFirstMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK,
+                                      ("%RGp-%RGp (MMIOEx/%s, flags %#X) consists of multiple chunks whereas the RAM somehow doesn't!\n",
+                                       GCPhys, GCPhysLast, pFirstMmio->RamRange.pszDesc, pFirstMmio->fFlags),
+                                      pgmUnlock(pVM),
+                                      VERR_PGM_PHYS_MMIO_EX_IPE);
+
             fRamExists = true;
             break;
         }
@@ -2790,165 +3331,289 @@ VMMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
         pRamPrev = pRam;
         pRam = pRam->pNextR3;
     }
-    if (fRamExists)
-    {
-        PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
-        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
-        while (cPagesLeft-- > 0)
-        {
-            AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
-                                  ("%RGp isn't a RAM page (%d) - mapping %RGp-%RGp (MMIO2/%s).\n",
-                                   GCPhys, PGM_PAGE_GET_TYPE(pPage), GCPhys, GCPhysLast, pCur->RamRange.pszDesc),
-                                  VERR_PGM_RAM_CONFLICT);
-            pPage++;
-        }
-    }
-    Log(("PGMR3PhysMMIO2Map: %RGp-%RGp fRamExists=%RTbool %s\n",
-         GCPhys, GCPhysLast, fRamExists, pCur->RamRange.pszDesc));
+    Log(("PGMR3PhysMMIOExMap: %RGp-%RGp fRamExists=%RTbool %s\n", GCPhys, GCPhysLast, fRamExists, pFirstMmio->RamRange.pszDesc));
+
 
     /*
      * Make the changes.
      */
-    pgmLock(pVM);
-
-    pCur->RamRange.GCPhys = GCPhys;
-    pCur->RamRange.GCPhysLast = GCPhysLast;
-    pCur->fMapped = true;
-    pCur->fOverlapping = fRamExists;
+    RTGCPHYS GCPhysCur = GCPhys;
+    for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
+    {
+        pCurMmio->RamRange.GCPhys = GCPhysCur;
+        pCurMmio->RamRange.GCPhysLast = GCPhysCur + pCurMmio->RamRange.cb - 1;
+        if (pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+        {
+            Assert(pCurMmio->RamRange.GCPhysLast == GCPhysLast);
+            break;
+        }
+        GCPhysCur += pCurMmio->RamRange.cb;
+    }
 
     if (fRamExists)
     {
-/** @todo use pgmR3PhysFreePageRange here. */
-        uint32_t            cPendingPages = 0;
-        PGMMFREEPAGESREQ    pReq;
-        int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
-        AssertLogRelRCReturn(rc, rc);
+        /*
+         * Make all the pages in the range MMIO/ZERO pages, freeing any
+         * RAM pages currently mapped here. This might not be 100% correct
+         * for PCI memory, but we're doing the same thing for MMIO2 pages.
+         *
+         * We replace this MMIO/ZERO pages with real pages in the MMIO2 case.
+         */
+        Assert(pFirstMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK); /* Only one chunk */
 
-        /* replace the pages, freeing all present RAM pages. */
-        PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
-        PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
-        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
-        while (cPagesLeft-- > 0)
+        int rc = pgmR3PhysFreePageRange(pVM, pRam, GCPhys, GCPhysLast, PGMPAGETYPE_MMIO);
+        AssertRCReturnStmt(rc, pgmUnlock(pVM), rc);
+
+        if (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
         {
-            rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPageDst, GCPhys);
-            AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
-
-            RTHCPHYS const HCPhys = PGM_PAGE_GET_HCPHYS(pPageSrc);
-            uint32_t const idPage = PGM_PAGE_GET_PAGEID(pPageSrc);
-            PGM_PAGE_SET_PAGEID(pVM, pPageDst, idPage);
-            PGM_PAGE_SET_HCPHYS(pVM, pPageDst, HCPhys);
-            PGM_PAGE_SET_TYPE(pVM, pPageDst, PGMPAGETYPE_MMIO2);
-            PGM_PAGE_SET_STATE(pVM, pPageDst, PGM_PAGE_STATE_ALLOCATED);
-            PGM_PAGE_SET_PDE_TYPE(pVM, pPageDst, PGM_PAGE_PDE_TYPE_DONTCARE);
-            PGM_PAGE_SET_PTE_INDEX(pVM, pPageDst, 0);
-            PGM_PAGE_SET_TRACKING(pVM, pPageDst, 0);
-
-            pVM->pgm.s.cZeroPages--;
-            GCPhys += PAGE_SIZE;
-            pPageSrc++;
-            pPageDst++;
+            /* replace the pages, freeing all present RAM pages. */
+            PPGMPAGE pPageSrc = &pFirstMmio->RamRange.aPages[0];
+            PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
+            uint32_t cPagesLeft = pFirstMmio->RamRange.cb >> PAGE_SHIFT;
+            while (cPagesLeft-- > 0)
+            {
+                Assert(PGM_PAGE_IS_MMIO(pPageDst));
+
+                RTHCPHYS const HCPhys = PGM_PAGE_GET_HCPHYS(pPageSrc);
+                uint32_t const idPage = PGM_PAGE_GET_PAGEID(pPageSrc);
+                PGM_PAGE_SET_PAGEID(pVM, pPageDst, idPage);
+                PGM_PAGE_SET_HCPHYS(pVM, pPageDst, HCPhys);
+                PGM_PAGE_SET_TYPE(pVM, pPageDst, PGMPAGETYPE_MMIO2);
+                PGM_PAGE_SET_STATE(pVM, pPageDst, PGM_PAGE_STATE_ALLOCATED);
+                PGM_PAGE_SET_PDE_TYPE(pVM, pPageDst, PGM_PAGE_PDE_TYPE_DONTCARE);
+                PGM_PAGE_SET_PTE_INDEX(pVM, pPageDst, 0);
+                PGM_PAGE_SET_TRACKING(pVM, pPageDst, 0);
+
+                pVM->pgm.s.cZeroPages--;
+                GCPhys += PAGE_SIZE;
+                pPageSrc++;
+                pPageDst++;
+            }
         }
 
         /* Flush physical page map TLB. */
         pgmPhysInvalidatePageMapTLB(pVM);
 
-        if (cPendingPages)
-        {
-            rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
-            AssertLogRelRCReturn(rc, rc);
-        }
-        GMMR3FreePagesCleanup(pReq);
-
         /* Force a PGM pool flush as guest ram references have been changed. */
         /** @todo not entirely SMP safe; assuming for now the guest takes care of
          *  this internally (not touch mapped mmio while changing the mapping). */
         PVMCPU pVCpu = VMMGetCpu(pVM);
         pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
         VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
-
-        pgmUnlock(pVM);
     }
     else
     {
-#ifdef VBOX_WITH_REM
-        RTGCPHYS cb = pCur->RamRange.cb;
-#endif
+        /*
+         * No RAM range, insert the ones prepared during registration.
+         */
+        for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
+        {
+            /* Clear the tracking data of pages we're going to reactivate. */
+            PPGMPAGE pPageSrc = &pCurMmio->RamRange.aPages[0];
+            uint32_t cPagesLeft = pCurMmio->RamRange.cb >> PAGE_SHIFT;
+            while (cPagesLeft-- > 0)
+            {
+                PGM_PAGE_SET_TRACKING(pVM, pPageSrc, 0);
+                PGM_PAGE_SET_PTE_INDEX(pVM, pPageSrc, 0);
+                pPageSrc++;
+            }
 
-        /* Clear the tracking data of pages we're going to reactivate. */
-        PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
-        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
-        while (cPagesLeft-- > 0)
+            /* link in the ram range */
+            pgmR3PhysLinkRamRange(pVM, &pCurMmio->RamRange, pRamPrev);
+
+            if (pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+            {
+                Assert(pCurMmio->RamRange.GCPhysLast == GCPhysLast);
+                break;
+            }
+            pRamPrev = &pCurMmio->RamRange;
+        }
+    }
+
+    /*
+     * Register the access handler if plain MMIO.
+     *
+     * We must register access handlers for each range since the access handler
+     * code refuses to deal with multiple ranges (and we can).
+     */
+    if (!(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2))
+    {
+        int rc = VINF_SUCCESS;
+        for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
         {
-            PGM_PAGE_SET_TRACKING(pVM, pPageSrc, 0);
-            PGM_PAGE_SET_PTE_INDEX(pVM, pPageSrc, 0);
-            pPageSrc++;
+            Assert(!(pCurMmio->fFlags & PGMREGMMIORANGE_F_MAPPED));
+            rc = pgmHandlerPhysicalExRegister(pVM, pCurMmio->pPhysHandlerR3, pCurMmio->RamRange.GCPhys,
+                                              pCurMmio->RamRange.GCPhysLast);
+            if (RT_FAILURE(rc))
+                break;
+            pCurMmio->fFlags |= PGMREGMMIORANGE_F_MAPPED; /* Use this to mark that the handler is registered. */
+            if (pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+            {
+                rc = IOMR3MmioExNotifyMapped(pVM, pFirstMmio->pPhysHandlerR3->pvUserR3, GCPhys);
+                break;
+            }
         }
+        if (RT_FAILURE(rc))
+        {
+            /* Almost impossible, but try clean up properly and get out of here. */
+            for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
+            {
+                if (pCurMmio->fFlags & PGMREGMMIORANGE_F_MAPPED)
+                {
+                    pCurMmio->fFlags &= ~PGMREGMMIORANGE_F_MAPPED;
+                    pgmHandlerPhysicalExDeregister(pVM, pCurMmio->pPhysHandlerR3);
+                }
 
-        /* link in the ram range */
-        pgmR3PhysLinkRamRange(pVM, &pCur->RamRange, pRamPrev);
-        pgmUnlock(pVM);
+                if (!fRamExists)
+                    pgmR3PhysUnlinkRamRange(pVM, &pCurMmio->RamRange);
+                else
+                {
+                    Assert(pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK); /* Only one chunk */
 
-#ifdef VBOX_WITH_REM
-        REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2);
-#endif
+                    uint32_t cPagesLeft = pCurMmio->RamRange.cb >> PAGE_SHIFT;
+                    PPGMPAGE pPageDst = &pRam->aPages[(pCurMmio->RamRange.GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
+                    while (cPagesLeft-- > 0)
+                    {
+                        PGM_PAGE_INIT_ZERO(pPageDst, pVM, PGMPAGETYPE_RAM);
+                        pPageDst++;
+                    }
+                }
+
+                pCurMmio->RamRange.GCPhys     = NIL_RTGCPHYS;
+                pCurMmio->RamRange.GCPhysLast = NIL_RTGCPHYS;
+                if (pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+                    break;
+            }
+
+            pgmUnlock(pVM);
+            return rc;
+        }
     }
 
+    /* 
+     * We're good, set the flags and invalid the mapping TLB.
+     */
+    for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
+    {
+        pCurMmio->fFlags |= PGMREGMMIORANGE_F_MAPPED;
+        if (fRamExists)
+            pCurMmio->fFlags |= PGMREGMMIORANGE_F_OVERLAPPING;
+        else
+            pCurMmio->fFlags &= ~PGMREGMMIORANGE_F_OVERLAPPING;
+        if (pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+            break;
+    }
     pgmPhysInvalidatePageMapTLB(pVM);
+
+    pgmUnlock(pVM);
+
+#ifdef VBOX_WITH_REM
+    /*
+     * Inform REM without holding the PGM lock.
+     */
+    if (!fRamExists && (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2))
+        REMR3NotifyPhysRamRegister(pVM, GCPhys, cbRange, REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2);
+#endif
     return VINF_SUCCESS;
 }
 
 
 /**
- * Unmaps a MMIO2 region.
+ * Unmaps a MMIO2 or a pre-registered MMIO region.
  *
  * This is done when a guest / the bios / state loading changes the
  * PCI config. The replacing of base memory has the same restrictions
  * as during registration, of course.
  */
-VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+VMMR3DECL(int) PGMR3PhysMMIOExUnmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS GCPhys)
 {
     /*
      * Validate input
      */
     VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
     AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
     AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
     AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
 
-    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
-    AssertReturn(pCur, VERR_NOT_FOUND);
-    AssertReturn(pCur->fMapped, VERR_WRONG_ORDER);
-    AssertReturn(pCur->RamRange.GCPhys == GCPhys, VERR_INVALID_PARAMETER);
-    Assert(pCur->RamRange.GCPhysLast != NIL_RTGCPHYS);
+    PPGMREGMMIORANGE pFirstMmio = pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion);
+    AssertReturn(pFirstMmio, VERR_NOT_FOUND);
+    Assert(pFirstMmio->fFlags & PGMREGMMIORANGE_F_FIRST_CHUNK);
+
+    PPGMREGMMIORANGE pLastMmio = pFirstMmio;
+    RTGCPHYS         cbRange   = 0;
+    for (;;)
+    {
+        AssertReturn(pLastMmio->fFlags & PGMREGMMIORANGE_F_MAPPED, VERR_WRONG_ORDER);
+        AssertReturn(pLastMmio->RamRange.GCPhys == GCPhys + cbRange, VERR_INVALID_PARAMETER);
+        Assert(pLastMmio->pDevInsR3 == pFirstMmio->pDevInsR3);
+        Assert(pLastMmio->iSubDev   == pFirstMmio->iSubDev);
+        Assert(pLastMmio->iRegion   == pFirstMmio->iRegion);
+        cbRange += pLastMmio->RamRange.cb;
+        if (pLastMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+            break;
+        pLastMmio = pLastMmio->pNextR3;
+    }
+
+    Log(("PGMR3PhysMMIOExUnmap: %RGp-%RGp %s\n",
+         pFirstMmio->RamRange.GCPhys, pLastMmio->RamRange.GCPhysLast, pFirstMmio->RamRange.pszDesc));
 
-    Log(("PGMR3PhysMMIO2Unmap: %RGp-%RGp %s\n",
-         pCur->RamRange.GCPhys, pCur->RamRange.GCPhysLast, pCur->RamRange.pszDesc));
+    int rc = pgmLock(pVM);
+    AssertRCReturn(rc, rc);
+    AssertReturnStmt(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MAPPED, pgmUnlock(pVM), VERR_WRONG_ORDER);
 
     /*
-     * Unmap it.
+     * If plain MMIO, we must deregister the handlers first.
      */
-    pgmLock(pVM);
+    if (!(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2))
+    {
+        PPGMREGMMIORANGE pCurMmio = pFirstMmio;
+        rc = pgmHandlerPhysicalExDeregister(pVM, pFirstMmio->pPhysHandlerR3);
+        AssertRCReturnStmt(rc, pgmUnlock(pVM), rc);
+        while (!(pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK))
+        {
+            pCurMmio = pCurMmio->pNextR3;
+            rc = pgmHandlerPhysicalExDeregister(pVM, pCurMmio->pPhysHandlerR3);
+            AssertRCReturnStmt(rc, pgmUnlock(pVM), VERR_PGM_PHYS_MMIO_EX_IPE);
+        }
 
+        IOMR3MmioExNotifyUnmapped(pVM, pFirstMmio->pPhysHandlerR3->pvUserR3, GCPhys);
+    }
+
+    /*
+     * Unmap it.
+     */
 #ifdef VBOX_WITH_REM
-    RTGCPHYS    GCPhysRangeREM;
-    RTGCPHYS    cbRangeREM;
-    bool        fInformREM;
+    RTGCPHYS        GCPhysRangeREM;
+    bool            fInformREM;
 #endif
-    if (pCur->fOverlapping)
+    if (pFirstMmio->fFlags & PGMREGMMIORANGE_F_OVERLAPPING)
     {
+        /*
+         * We've replaced RAM, replace with zero pages.
+         *
+         * Note! This is where we might differ a little from a real system, because
+         *       it's likely to just show the RAM pages as they were before the
+         *       MMIO/MMIO2 region was mapped here.
+         */
+        /* Only one chunk allowed when overlapping! */
+        Assert(pFirstMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK);
+
         /* Restore the RAM pages we've replaced. */
         PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
-        while (pRam->GCPhys > pCur->RamRange.GCPhysLast)
+        while (pRam->GCPhys > pFirstMmio->RamRange.GCPhysLast)
             pRam = pRam->pNextR3;
 
-        PPGMPAGE pPageDst = &pRam->aPages[(pCur->RamRange.GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
-        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
+        uint32_t cPagesLeft = pFirstMmio->RamRange.cb >> PAGE_SHIFT;
+        if (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
+            pVM->pgm.s.cZeroPages += cPagesLeft;
+
+        PPGMPAGE pPageDst = &pRam->aPages[(pFirstMmio->RamRange.GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
         while (cPagesLeft-- > 0)
         {
             PGM_PAGE_INIT_ZERO(pPageDst, pVM, PGMPAGETYPE_RAM);
-            pVM->pgm.s.cZeroPages++;
             pPageDst++;
         }
 
@@ -2956,25 +3621,34 @@ VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion
         pgmPhysInvalidatePageMapTLB(pVM);
 #ifdef VBOX_WITH_REM
         GCPhysRangeREM = NIL_RTGCPHYS;  /* shuts up gcc */
-        cbRangeREM     = RTGCPHYS_MAX;  /* ditto */
         fInformREM     = false;
 #endif
+
+        /* Update range state. */
+        pFirstMmio->RamRange.GCPhys = NIL_RTGCPHYS;
+        pFirstMmio->RamRange.GCPhysLast = NIL_RTGCPHYS;
+        pFirstMmio->fFlags &= ~(PGMREGMMIORANGE_F_OVERLAPPING | PGMREGMMIORANGE_F_MAPPED);
     }
     else
     {
+        /*
+         * Unlink the chunks related to the MMIO/MMIO2 region.
+         */
 #ifdef VBOX_WITH_REM
-        GCPhysRangeREM = pCur->RamRange.GCPhys;
-        cbRangeREM     = pCur->RamRange.cb;
-        fInformREM     = true;
+        GCPhysRangeREM = pFirstMmio->RamRange.GCPhys;
+        fInformREM     = RT_BOOL(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2);
 #endif
-        pgmR3PhysUnlinkRamRange(pVM, &pCur->RamRange);
+        for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
+        {
+            pgmR3PhysUnlinkRamRange(pVM, &pCurMmio->RamRange);
+            pCurMmio->RamRange.GCPhys = NIL_RTGCPHYS;
+            pCurMmio->RamRange.GCPhysLast = NIL_RTGCPHYS;
+            pCurMmio->fFlags &= ~(PGMREGMMIORANGE_F_OVERLAPPING | PGMREGMMIORANGE_F_MAPPED);
+            if (pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK)
+                break;
+        }
     }
 
-    pCur->RamRange.GCPhys = NIL_RTGCPHYS;
-    pCur->RamRange.GCPhysLast = NIL_RTGCPHYS;
-    pCur->fOverlapping = false;
-    pCur->fMapped = false;
-
     /* Force a PGM pool flush as guest ram references have been changed. */
     /** @todo not entirely SMP safe; assuming for now the guest takes care
      *  of this internally (not touch mapped mmio while changing the
@@ -2985,11 +3659,15 @@ VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion
 
     pgmPhysInvalidatePageMapTLB(pVM);
     pgmPhysInvalidRamRangeTlbs(pVM);
+
     pgmUnlock(pVM);
 
 #ifdef VBOX_WITH_REM
+    /*
+     * Inform REM without holding the PGM lock.
+     */
     if (fInformREM)
-        REMR3NotifyPhysRamDeregister(pVM, GCPhysRangeREM, cbRangeREM);
+        REMR3NotifyPhysRamDeregister(pVM, GCPhysRangeREM, cbRange);
 #endif
 
     return VINF_SUCCESS;
@@ -2997,14 +3675,15 @@ VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion
 
 
 /**
- * Checks if the given address is an MMIO2 base address or not.
+ * Checks if the given address is an MMIO2 or pre-registered MMIO base address
+ * or not.
  *
  * @returns true/false accordingly.
  * @param   pVM             The cross context VM structure.
  * @param   pDevIns         The owner of the memory, optional.
  * @param   GCPhys          The address to check.
  */
-VMMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
+VMMR3DECL(bool) PGMR3PhysMMIOExIsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
 {
     /*
      * Validate input
@@ -3019,12 +3698,13 @@ VMMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhy
      * Search the list.
      */
     pgmLock(pVM);
-    for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
-        if (pCur->RamRange.GCPhys == GCPhys)
+    for (PPGMREGMMIORANGE pCurMmio = pVM->pgm.s.pRegMmioRangesR3; pCurMmio; pCurMmio = pCurMmio->pNextR3)
+        if (pCurMmio->RamRange.GCPhys == GCPhys)
         {
-            Assert(pCur->fMapped);
+            Assert(pCurMmio->fFlags & PGMREGMMIORANGE_F_MAPPED);
+            bool fRet = RT_BOOL(pCurMmio->fFlags & PGMREGMMIORANGE_F_FIRST_CHUNK);
             pgmUnlock(pVM);
-            return true;
+            return fRet;
         }
     pgmUnlock(pVM);
     return false;
@@ -3040,25 +3720,36 @@ VMMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhy
  * @returns VBox status code.
  * @param   pVM             The cross context VM structure.
  * @param   pDevIns         The owner of the memory, optional.
+ * @param   iSubDev         Sub-device number.
  * @param   iRegion         The region.
  * @param   off             The page expressed an offset into the MMIO2 region.
  * @param   pHCPhys         Where to store the result.
  */
-VMMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys)
+VMMR3_INT_DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion,
+                                            RTGCPHYS off, PRTHCPHYS pHCPhys)
 {
     /*
      * Validate input
      */
     VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
     AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
 
     pgmLock(pVM);
-    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
-    AssertReturn(pCur, VERR_NOT_FOUND);
-    AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
+    PPGMREGMMIORANGE pCurMmio = pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion);
+    AssertReturn(pCurMmio, VERR_NOT_FOUND);
+    AssertReturn(pCurMmio->fFlags & (PGMREGMMIORANGE_F_MMIO2 | PGMREGMMIORANGE_F_FIRST_CHUNK), VERR_WRONG_TYPE);
+
+    while (   off >= pCurMmio->RamRange.cb
+           && !(pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK))
+    {
+        off -= pCurMmio->RamRange.cb;
+        pCurMmio = pCurMmio->pNextR3;
+    }
+    AssertReturn(off < pCurMmio->RamRange.cb, VERR_INVALID_PARAMETER);
 
-    PCPGMPAGE pPage = &pCur->RamRange.aPages[off >> PAGE_SHIFT];
+    PCPGMPAGE pPage = &pCurMmio->RamRange.aPages[off >> PAGE_SHIFT];
     *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage);
     pgmUnlock(pVM);
     return VINF_SUCCESS;
@@ -3075,33 +3766,36 @@ VMMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRe
  *
  * @param   pVM         The cross context VM structure.
  * @param   pDevIns     The device owning the MMIO2 memory.
+ * @param   iSubDev     The sub-device number.
  * @param   iRegion     The region.
  * @param   off         The offset into the region. Must be page aligned.
  * @param   cb          The number of bytes to map. Must be page aligned.
  * @param   pszDesc     Mapping description.
  * @param   pR0Ptr      Where to store the R0 address.
  */
-VMMR3DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
-                                       const char *pszDesc, PRTR0PTR pR0Ptr)
+VMMR3_INT_DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion,
+                                            RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTR0PTR pR0Ptr)
 {
     /*
      * Validate input.
      */
     VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
     AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
     AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
 
-    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
-    AssertReturn(pCur, VERR_NOT_FOUND);
-    AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
-    AssertReturn(cb <= pCur->RamRange.cb, VERR_INVALID_PARAMETER);
-    AssertReturn(off + cb <= pCur->RamRange.cb, VERR_INVALID_PARAMETER);
+    PPGMREGMMIORANGE pFirstRegMmio = pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion);
+    AssertReturn(pFirstRegMmio, VERR_NOT_FOUND);
+    AssertReturn(pFirstRegMmio->fFlags & (PGMREGMMIORANGE_F_MMIO2 | PGMREGMMIORANGE_F_FIRST_CHUNK), VERR_WRONG_TYPE);
+    AssertReturn(off < pFirstRegMmio->RamRange.cb, VERR_INVALID_PARAMETER);
+    AssertReturn(cb <= pFirstRegMmio->RamRange.cb, VERR_INVALID_PARAMETER);
+    AssertReturn(off + cb <= pFirstRegMmio->RamRange.cb, VERR_INVALID_PARAMETER);
     NOREF(pszDesc);
 
     /*
      * Pass the request on to the support library/driver.
      */
-    int rc = SUPR3PageMapKernel(pCur->pvR3, off, cb, 0, pR0Ptr);
+    int rc = SUPR3PageMapKernel(pFirstRegMmio->pvR3, off, cb, 0, pR0Ptr);
 
     return rc;
 }
diff --git a/src/VBox/VMM/VMMR3/PGMSavedState.cpp b/src/VBox/VMM/VMMR3/PGMSavedState.cpp
index 9e9b0d0..d915f5d 100644
--- a/src/VBox/VMM/VMMR3/PGMSavedState.cpp
+++ b/src/VBox/VMM/VMMR3/PGMSavedState.cpp
@@ -641,27 +641,30 @@ static int pgmR3PrepMmio2Pages(PVM pVM)
      * ASSUME nothing changes here.
      */
     pgmLock(pVM);
-    for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
+    for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
     {
-        uint32_t const  cPages = pMmio2->RamRange.cb >> PAGE_SHIFT;
-        pgmUnlock(pVM);
-
-        PPGMLIVESAVEMMIO2PAGE paLSPages = (PPGMLIVESAVEMMIO2PAGE)MMR3HeapAllocZ(pVM, MM_TAG_PGM, sizeof(PGMLIVESAVEMMIO2PAGE) * cPages);
-        if (!paLSPages)
-            return VERR_NO_MEMORY;
-        for (uint32_t iPage = 0; iPage < cPages; iPage++)
+        if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
         {
-            /* Initialize it as a dirty zero page. */
-            paLSPages[iPage].fDirty          = true;
-            paLSPages[iPage].cUnchangedScans = 0;
-            paLSPages[iPage].fZero           = true;
-            paLSPages[iPage].u32CrcH1        = PGM_STATE_CRC32_ZERO_HALF_PAGE;
-            paLSPages[iPage].u32CrcH2        = PGM_STATE_CRC32_ZERO_HALF_PAGE;
-        }
+            uint32_t const  cPages = pRegMmio->RamRange.cb >> PAGE_SHIFT;
+            pgmUnlock(pVM);
 
-        pgmLock(pVM);
-        pMmio2->paLSPages = paLSPages;
-        pVM->pgm.s.LiveSave.Mmio2.cDirtyPages += cPages;
+            PPGMLIVESAVEMMIO2PAGE paLSPages = (PPGMLIVESAVEMMIO2PAGE)MMR3HeapAllocZ(pVM, MM_TAG_PGM, sizeof(PGMLIVESAVEMMIO2PAGE) * cPages);
+            if (!paLSPages)
+                return VERR_NO_MEMORY;
+            for (uint32_t iPage = 0; iPage < cPages; iPage++)
+            {
+                /* Initialize it as a dirty zero page. */
+                paLSPages[iPage].fDirty          = true;
+                paLSPages[iPage].cUnchangedScans = 0;
+                paLSPages[iPage].fZero           = true;
+                paLSPages[iPage].u32CrcH1        = PGM_STATE_CRC32_ZERO_HALF_PAGE;
+                paLSPages[iPage].u32CrcH2        = PGM_STATE_CRC32_ZERO_HALF_PAGE;
+            }
+
+            pgmLock(pVM);
+            pRegMmio->paLSPages = paLSPages;
+            pVM->pgm.s.LiveSave.Mmio2.cDirtyPages += cPages;
+        }
     }
     pgmUnlock(pVM);
     return VINF_SUCCESS;
@@ -679,17 +682,21 @@ static int pgmR3SaveMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)
 {
     pgmLock(pVM);
     uint8_t id = 1;
-    for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3, id++)
+    for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
     {
-        pMmio2->idSavedState = id;
-        SSMR3PutU8(pSSM, id);
-        SSMR3PutStrZ(pSSM, pMmio2->pDevInsR3->pReg->szName);
-        SSMR3PutU32(pSSM, pMmio2->pDevInsR3->iInstance);
-        SSMR3PutU8(pSSM, pMmio2->iRegion);
-        SSMR3PutStrZ(pSSM, pMmio2->RamRange.pszDesc);
-        int rc = SSMR3PutGCPhys(pSSM, pMmio2->RamRange.cb);
-        if (RT_FAILURE(rc))
-            break;
+        if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
+        {
+            pRegMmio->idSavedState = id;
+            SSMR3PutU8(pSSM, id);
+            SSMR3PutStrZ(pSSM, pRegMmio->pDevInsR3->pReg->szName);
+            SSMR3PutU32(pSSM, pRegMmio->pDevInsR3->iInstance);
+            SSMR3PutU8(pSSM, pRegMmio->iRegion);
+            SSMR3PutStrZ(pSSM, pRegMmio->RamRange.pszDesc);
+            int rc = SSMR3PutGCPhys(pSSM, pRegMmio->RamRange.cb);
+            if (RT_FAILURE(rc))
+                break;
+            id++;
+        }
     }
     pgmUnlock(pVM);
     return SSMR3PutU8(pSSM, UINT8_MAX);
@@ -708,8 +715,9 @@ static int pgmR3LoadMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)
 {
     PGM_LOCK_ASSERT_OWNER(pVM);
 
-    for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
-        pMmio2->idSavedState = UINT8_MAX;
+    for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
+        if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
+            pRegMmio->idSavedState = UINT8_MAX;
 
     for (;;)
     {
@@ -722,8 +730,10 @@ static int pgmR3LoadMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)
             return rc;
         if (id == UINT8_MAX)
         {
-            for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
-                AssertLogRelMsg(pMmio2->idSavedState != UINT8_MAX, ("%s\n", pMmio2->RamRange.pszDesc));
+            for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
+                AssertLogRelMsg(   pRegMmio->idSavedState != UINT8_MAX
+                                || !(pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2),
+                                ("%s\n", pRegMmio->RamRange.pszDesc));
             return VINF_SUCCESS;        /* the end */
         }
         AssertLogRelReturn(id != 0, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
@@ -748,19 +758,20 @@ static int pgmR3LoadMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)
         /*
          * Locate a matching MMIO2 range.
          */
-        PPGMMMIO2RANGE pMmio2;
-        for (pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
+        PPGMREGMMIORANGE pRegMmio;
+        for (pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
         {
-            if (    pMmio2->idSavedState == UINT8_MAX
-                &&  pMmio2->iRegion == iRegion
-                &&  pMmio2->pDevInsR3->iInstance == uInstance
-                &&  !strcmp(pMmio2->pDevInsR3->pReg->szName, szDevName))
+            if (    pRegMmio->idSavedState == UINT8_MAX
+                &&  pRegMmio->iRegion == iRegion
+                &&  pRegMmio->pDevInsR3->iInstance == uInstance
+                &&  (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
+                &&  !strcmp(pRegMmio->pDevInsR3->pReg->szName, szDevName))
             {
-                pMmio2->idSavedState = id;
+                pRegMmio->idSavedState = id;
                 break;
             }
         }
-        if (!pMmio2)
+        if (!pRegMmio)
             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to locate a MMIO2 range called '%s' owned by %s/%u, region %d"),
                                     szDesc, szDevName, uInstance, iRegion);
 
@@ -768,13 +779,13 @@ static int pgmR3LoadMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)
          * Validate the configuration, the size of the MMIO2 region should be
          * the same.
          */
-        if (cb != pMmio2->RamRange.cb)
+        if (cb != pRegMmio->RamRange.cb)
         {
             LogRel(("PGM: MMIO2 region \"%s\" size mismatch: saved=%RGp config=%RGp\n",
-                    pMmio2->RamRange.pszDesc, cb, pMmio2->RamRange.cb));
-            if (cb > pMmio2->RamRange.cb) /* bad idea? */
+                    pRegMmio->RamRange.pszDesc, cb, pRegMmio->RamRange.cb));
+            if (cb > pRegMmio->RamRange.cb) /* bad idea? */
                 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("MMIO2 region \"%s\" size mismatch: saved=%RGp config=%RGp"),
-                                        pMmio2->RamRange.pszDesc, cb, pMmio2->RamRange.cb);
+                                        pRegMmio->RamRange.pszDesc, cb, pRegMmio->RamRange.cb);
         }
     } /* forever */
 }
@@ -872,20 +883,21 @@ static void pgmR3ScanMmio2Pages(PVM pVM, uint32_t uPass)
         return;
 
     pgmLock(pVM);                       /* paranoia */
-    for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
-    {
-        PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages;
-        uint32_t              cPages    = pMmio2->RamRange.cb >> PAGE_SHIFT;
-        pgmUnlock(pVM);
-
-        for (uint32_t iPage = 0; iPage < cPages; iPage++)
+    for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
+        if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
         {
-            uint8_t const *pbPage = (uint8_t const *)pMmio2->pvR3 + iPage * PAGE_SIZE;
-            pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]);
-        }
+            PPGMLIVESAVEMMIO2PAGE paLSPages = pRegMmio->paLSPages;
+            uint32_t              cPages    = pRegMmio->RamRange.cb >> PAGE_SHIFT;
+            pgmUnlock(pVM);
 
-        pgmLock(pVM);
-    }
+            for (uint32_t iPage = 0; iPage < cPages; iPage++)
+            {
+                uint8_t const *pbPage = (uint8_t const *)pRegMmio->pvR3 + iPage * PAGE_SIZE;
+                pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]);
+            }
+
+            pgmLock(pVM);
+        }
     pgmUnlock(pVM);
 
 }
@@ -912,52 +924,53 @@ static int pgmR3SaveMmio2Pages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave, uint32_
          * The mop up round.
          */
         pgmLock(pVM);
-        for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3;
-             pMmio2 && RT_SUCCESS(rc);
-             pMmio2 = pMmio2->pNextR3)
-        {
-            PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages;
-            uint8_t const        *pbPage    = (uint8_t const *)pMmio2->RamRange.pvR3;
-            uint32_t              cPages    = pMmio2->RamRange.cb >> PAGE_SHIFT;
-            uint32_t              iPageLast = cPages;
-            for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)
+        for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3;
+             pRegMmio && RT_SUCCESS(rc);
+             pRegMmio = pRegMmio->pNextR3)
+            if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
             {
-                uint8_t u8Type;
-                if (!fLiveSave)
-                    u8Type = ASMMemIsZeroPage(pbPage) ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;
-                else
+                PPGMLIVESAVEMMIO2PAGE paLSPages = pRegMmio->paLSPages;
+                uint8_t const        *pbPage    = (uint8_t const *)pRegMmio->RamRange.pvR3;
+                uint32_t              cPages    = pRegMmio->RamRange.cb >> PAGE_SHIFT;
+                uint32_t              iPageLast = cPages;
+                for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)
                 {
-                    /* Try figure if it's a clean page, compare the SHA-1 to be really sure. */
-                    if (   !paLSPages[iPage].fDirty
-                        && !pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]))
+                    uint8_t u8Type;
+                    if (!fLiveSave)
+                        u8Type = ASMMemIsZeroPage(pbPage) ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;
+                    else
                     {
-                        if (paLSPages[iPage].fZero)
-                            continue;
+                        /* Try figure if it's a clean page, compare the SHA-1 to be really sure. */
+                        if (   !paLSPages[iPage].fDirty
+                            && !pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]))
+                        {
+                            if (paLSPages[iPage].fZero)
+                                continue;
 
-                        uint8_t abSha1Hash[RTSHA1_HASH_SIZE];
-                        RTSha1(pbPage, PAGE_SIZE, abSha1Hash);
-                        if (!memcmp(abSha1Hash, paLSPages[iPage].abSha1Saved, sizeof(abSha1Hash)))
-                            continue;
+                            uint8_t abSha1Hash[RTSHA1_HASH_SIZE];
+                            RTSha1(pbPage, PAGE_SIZE, abSha1Hash);
+                            if (!memcmp(abSha1Hash, paLSPages[iPage].abSha1Saved, sizeof(abSha1Hash)))
+                                continue;
+                        }
+                        u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;
+                        pVM->pgm.s.LiveSave.cSavedPages++;
                     }
-                    u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;
-                    pVM->pgm.s.LiveSave.cSavedPages++;
-                }
 
-                if (iPage != 0 && iPage == iPageLast + 1)
-                    rc = SSMR3PutU8(pSSM, u8Type);
-                else
-                {
-                    SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR);
-                    SSMR3PutU8(pSSM, pMmio2->idSavedState);
-                    rc = SSMR3PutU32(pSSM, iPage);
+                    if (iPage != 0 && iPage == iPageLast + 1)
+                        rc = SSMR3PutU8(pSSM, u8Type);
+                    else
+                    {
+                        SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR);
+                        SSMR3PutU8(pSSM, pRegMmio->idSavedState);
+                        rc = SSMR3PutU32(pSSM, iPage);
+                    }
+                    if (u8Type == PGM_STATE_REC_MMIO2_RAW)
+                        rc = SSMR3PutMem(pSSM, pbPage, PAGE_SIZE);
+                    if (RT_FAILURE(rc))
+                        break;
+                    iPageLast = iPage;
                 }
-                if (u8Type == PGM_STATE_REC_MMIO2_RAW)
-                    rc = SSMR3PutMem(pSSM, pbPage, PAGE_SIZE);
-                if (RT_FAILURE(rc))
-                    break;
-                iPageLast = iPage;
             }
-        }
         pgmUnlock(pVM);
     }
     /*
@@ -969,61 +982,62 @@ static int pgmR3SaveMmio2Pages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave, uint32_
              || (uPass & 3) == 2)
     {
         pgmLock(pVM);
-        for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3;
-             pMmio2 && RT_SUCCESS(rc);
-             pMmio2 = pMmio2->pNextR3)
-        {
-            PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages;
-            uint8_t const        *pbPage    = (uint8_t const *)pMmio2->RamRange.pvR3;
-            uint32_t              cPages    = pMmio2->RamRange.cb >> PAGE_SHIFT;
-            uint32_t              iPageLast = cPages;
-            pgmUnlock(pVM);
-
-            for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)
+        for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3;
+             pRegMmio && RT_SUCCESS(rc);
+             pRegMmio = pRegMmio->pNextR3)
+            if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
             {
-                /* Skip clean pages and pages which hasn't quiesced. */
-                if (!paLSPages[iPage].fDirty)
-                    continue;
-                if (paLSPages[iPage].cUnchangedScans < 3)
-                    continue;
-                if (pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]))
-                    continue;
-
-                /* Save it. */
-                bool const fZero = paLSPages[iPage].fZero;
-                uint8_t abPage[PAGE_SIZE];
-                if (!fZero)
-                {
-                    memcpy(abPage, pbPage, PAGE_SIZE);
-                    RTSha1(abPage, PAGE_SIZE, paLSPages[iPage].abSha1Saved);
-                }
+                PPGMLIVESAVEMMIO2PAGE paLSPages = pRegMmio->paLSPages;
+                uint8_t const        *pbPage    = (uint8_t const *)pRegMmio->RamRange.pvR3;
+                uint32_t              cPages    = pRegMmio->RamRange.cb >> PAGE_SHIFT;
+                uint32_t              iPageLast = cPages;
+                pgmUnlock(pVM);
 
-                uint8_t u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;
-                if (iPage != 0 && iPage == iPageLast + 1)
-                    rc = SSMR3PutU8(pSSM, u8Type);
-                else
+                for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)
                 {
-                    SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR);
-                    SSMR3PutU8(pSSM, pMmio2->idSavedState);
-                    rc = SSMR3PutU32(pSSM, iPage);
+                    /* Skip clean pages and pages which hasn't quiesced. */
+                    if (!paLSPages[iPage].fDirty)
+                        continue;
+                    if (paLSPages[iPage].cUnchangedScans < 3)
+                        continue;
+                    if (pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]))
+                        continue;
+
+                    /* Save it. */
+                    bool const fZero = paLSPages[iPage].fZero;
+                    uint8_t abPage[PAGE_SIZE];
+                    if (!fZero)
+                    {
+                        memcpy(abPage, pbPage, PAGE_SIZE);
+                        RTSha1(abPage, PAGE_SIZE, paLSPages[iPage].abSha1Saved);
+                    }
+
+                    uint8_t u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;
+                    if (iPage != 0 && iPage == iPageLast + 1)
+                        rc = SSMR3PutU8(pSSM, u8Type);
+                    else
+                    {
+                        SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR);
+                        SSMR3PutU8(pSSM, pRegMmio->idSavedState);
+                        rc = SSMR3PutU32(pSSM, iPage);
+                    }
+                    if (u8Type == PGM_STATE_REC_MMIO2_RAW)
+                        rc = SSMR3PutMem(pSSM, abPage, PAGE_SIZE);
+                    if (RT_FAILURE(rc))
+                        break;
+
+                    /* Housekeeping. */
+                    paLSPages[iPage].fDirty = false;
+                    pVM->pgm.s.LiveSave.Mmio2.cDirtyPages--;
+                    pVM->pgm.s.LiveSave.Mmio2.cReadyPages++;
+                    if (u8Type == PGM_STATE_REC_MMIO2_ZERO)
+                        pVM->pgm.s.LiveSave.Mmio2.cZeroPages++;
+                    pVM->pgm.s.LiveSave.cSavedPages++;
+                    iPageLast = iPage;
                 }
-                if (u8Type == PGM_STATE_REC_MMIO2_RAW)
-                    rc = SSMR3PutMem(pSSM, abPage, PAGE_SIZE);
-                if (RT_FAILURE(rc))
-                    break;
-
-                /* Housekeeping. */
-                paLSPages[iPage].fDirty = false;
-                pVM->pgm.s.LiveSave.Mmio2.cDirtyPages--;
-                pVM->pgm.s.LiveSave.Mmio2.cReadyPages++;
-                if (u8Type == PGM_STATE_REC_MMIO2_ZERO)
-                    pVM->pgm.s.LiveSave.Mmio2.cZeroPages++;
-                pVM->pgm.s.LiveSave.cSavedPages++;
-                iPageLast = iPage;
-            }
 
-            pgmLock(pVM);
-        }
+                pgmLock(pVM);
+            }
         pgmUnlock(pVM);
     }
 
@@ -1043,17 +1057,18 @@ static void pgmR3DoneMmio2Pages(PVM pVM)
      * We do the freeing outside the lock in case the VM is running.
      */
     pgmLock(pVM);
-    for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
-    {
-        void *pvMmio2ToFree = pMmio2->paLSPages;
-        if (pvMmio2ToFree)
+    for (PPGMREGMMIORANGE pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
+        if (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
         {
-            pMmio2->paLSPages = NULL;
-            pgmUnlock(pVM);
-            MMR3HeapFree(pvMmio2ToFree);
-            pgmLock(pVM);
+            void *pvMmio2ToFree = pRegMmio->paLSPages;
+            if (pvMmio2ToFree)
+            {
+                pRegMmio->paLSPages = NULL;
+                pgmUnlock(pVM);
+                MMR3HeapFree(pvMmio2ToFree);
+                pgmLock(pVM);
+            }
         }
-    }
     pgmUnlock(pVM);
 }
 
@@ -2612,12 +2627,12 @@ static int pgmR3LoadMemory(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t
     /*
      * Process page records until we hit the terminator.
      */
-    RTGCPHYS        GCPhys   = NIL_RTGCPHYS;
-    PPGMRAMRANGE    pRamHint = NULL;
-    uint8_t         id       = UINT8_MAX;
-    uint32_t        iPage    = UINT32_MAX - 10;
-    PPGMROMRANGE    pRom     = NULL;
-    PPGMMMIO2RANGE  pMmio2   = NULL;
+    RTGCPHYS            GCPhys   = NIL_RTGCPHYS;
+    PPGMRAMRANGE        pRamHint = NULL;
+    uint8_t             id       = UINT8_MAX;
+    uint32_t            iPage    = UINT32_MAX - 10;
+    PPGMROMRANGE        pRom     = NULL;
+    PPGMREGMMIORANGE    pRegMmio = NULL;
 
     /*
      * We batch up pages that should be freed instead of calling GMM for
@@ -2791,16 +2806,17 @@ static int pgmR3LoadMemory(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t
                     if (RT_FAILURE(rc))
                         return rc;
                 }
-                if (    !pMmio2
-                    ||  pMmio2->idSavedState != id)
+                if (   !pRegMmio
+                    || pRegMmio->idSavedState != id)
                 {
-                    for (pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)
-                        if (pMmio2->idSavedState == id)
+                    for (pRegMmio = pVM->pgm.s.pRegMmioRangesR3; pRegMmio; pRegMmio = pRegMmio->pNextR3)
+                        if (   pRegMmio->idSavedState == id
+                            && (pRegMmio->fFlags & PGMREGMMIORANGE_F_MMIO2))
                             break;
-                    AssertLogRelMsgReturn(pMmio2, ("id=%#u iPage=%#x\n", id, iPage), VERR_PGM_SAVED_MMIO2_RANGE_NOT_FOUND);
+                    AssertLogRelMsgReturn(pRegMmio, ("id=%#u iPage=%#x\n", id, iPage), VERR_PGM_SAVED_MMIO2_RANGE_NOT_FOUND);
                 }
-                AssertLogRelMsgReturn(iPage < (pMmio2->RamRange.cb >> PAGE_SHIFT), ("iPage=%#x cb=%RGp %s\n", iPage, pMmio2->RamRange.cb, pMmio2->RamRange.pszDesc), VERR_PGM_SAVED_MMIO2_PAGE_NOT_FOUND);
-                void *pvDstPage = (uint8_t *)pMmio2->RamRange.pvR3 + ((size_t)iPage << PAGE_SHIFT);
+                AssertLogRelMsgReturn(iPage < (pRegMmio->RamRange.cb >> PAGE_SHIFT), ("iPage=%#x cb=%RGp %s\n", iPage, pRegMmio->RamRange.cb, pRegMmio->RamRange.pszDesc), VERR_PGM_SAVED_MMIO2_PAGE_NOT_FOUND);
+                void *pvDstPage = (uint8_t *)pRegMmio->RamRange.pvR3 + ((size_t)iPage << PAGE_SHIFT);
 
                 /*
                  * Load the page bits.
diff --git a/src/VBox/VMM/VMMRC/PDMRCDevice.cpp b/src/VBox/VMM/VMMRC/PDMRCDevice.cpp
index a0c787c..89849d9 100644
--- a/src/VBox/VMM/VMMRC/PDMRCDevice.cpp
+++ b/src/VBox/VMM/VMMRC/PDMRCDevice.cpp
@@ -20,6 +20,7 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_PDM_DEVICE
+#define PDMPCIDEV_INCLUDE_PRIVATE  /* Hack to get pdmpcidevint.h included at the right point. */
 #include "PDMInternal.h"
 #include <VBox/vmm/pdm.h>
 #include <VBox/vmm/pgm.h>
@@ -64,18 +65,21 @@ static bool pdmRCIsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc);
  */
 
 /** @interface_method_impl{PDMDEVHLPRC,pfnPCIPhysRead} */
-static DECLCALLBACK(int) pdmRCDevHlp_PCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+static DECLCALLBACK(int) pdmRCDevHlp_PCIPhysRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                                 void *pvBuf, size_t cbRead)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevRC;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
 
 #ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
     /*
      * Just check the busmaster setting here and forward the request to the generic read helper.
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceRC;
-    AssertReleaseMsg(pPciDev, ("No PCI device registered!\n"));
-
-    if (!PCIDevIsBusmaster(pPciDev))
+    if (PCIDevIsBusmaster(pPciDev))
+    { /* likely */ }
+    else
     {
         Log(("pdmRCDevHlp_PCIPhysRead: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbRead=%#zx\n",
              pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbRead));
@@ -88,36 +92,44 @@ static DECLCALLBACK(int) pdmRCDevHlp_PCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GC
 
 
 /** @interface_method_impl{PDMDEVHLPRC,pfnPCIPhysWrite} */
-static DECLCALLBACK(int) pdmRCDevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+static DECLCALLBACK(int) pdmRCDevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
+                                                  const void *pvBuf, size_t cbWrite)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevRC;
+    AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
 
+#ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
     /*
      * Just check the busmaster setting here and forward the request to the generic read helper.
      */
-    PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceRC;
-    AssertReleaseMsg(pPciDev, ("No PCI device registered!\n"));
-
-    if (!PCIDevIsBusmaster(pPciDev))
+    if (PCIDevIsBusmaster(pPciDev))
+    { /* likely*/ }
+    else
     {
         Log(("pdmRCDevHlp_PCIPhysWrite: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbWrite=%#zx\n",
              pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbWrite));
         return VERR_PDM_NOT_PCI_BUS_MASTER;
     }
+#endif
 
     return pDevIns->pHlpRC->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
 }
 
 
 /** @interface_method_impl{PDMDEVHLPRC,pfnPCISetIrq} */
-static DECLCALLBACK(void) pdmRCDevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
+static DECLCALLBACK(void) pdmRCDevHlp_PCISetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
-    LogFlow(("pdmRCDevHlp_PCISetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel));
+    if (!pPciDev) /* NULL is an alias for the default PCI device. */
+        pPciDev = pDevIns->Internal.s.pHeadPciDevRC;
+    AssertReturnVoid(pPciDev);
+    LogFlow(("pdmRCDevHlp_PCISetIrq: caller=%p/%d: pPciDev=%p:{%#x} iIrq=%d iLevel=%d\n",
+             pDevIns, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iIrq, iLevel));
 
     PVM         pVM     = pDevIns->Internal.s.pVMRC;
-    PPCIDEVICE  pPciDev = pDevIns->Internal.s.pPciDeviceRC;
-    PPDMPCIBUS  pPciBus = pDevIns->Internal.s.pPciBusRC;
+    PPDMPCIBUS  pPciBus = pPciDev->Int.s.pPdmBusRC;
 
     pdmLock(pVM);
     uint32_t uTagSrc;
@@ -153,9 +165,10 @@ static DECLCALLBACK(void) pdmRCDevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, in
 
         pTask->enmOp = PDMDEVHLPTASKOP_PCI_SET_IRQ;
         pTask->pDevInsR3 = PDMDEVINS_2_R3PTR(pDevIns);
-        pTask->u.SetIRQ.iIrq = iIrq;
-        pTask->u.SetIRQ.iLevel = iLevel;
-        pTask->u.SetIRQ.uTagSrc = uTagSrc;
+        pTask->u.PciSetIRQ.iIrq = iIrq;
+        pTask->u.PciSetIRQ.iLevel = iLevel;
+        pTask->u.PciSetIRQ.uTagSrc = uTagSrc;
+        pTask->u.PciSetIRQ.pPciDevR3 = MMHyperRCToR3(pVM, pPciDev);
 
         PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueRC, &pTask->Core, 0);
     }
@@ -391,6 +404,16 @@ extern DECLEXPORT(const PDMDEVHLPRC) g_pdmRCDevHlp =
     pdmRCDevHlp_TMTimeVirtGetFreq,
     pdmRCDevHlp_TMTimeVirtGetNano,
     pdmRCDevHlp_DBGFTraceBuf,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
     PDM_DEVHLPRC_VERSION
 };
 
@@ -741,9 +764,9 @@ static DECLCALLBACK(void) pdmRCPciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq,
         {
             pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ;
             pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
-            pTask->u.SetIRQ.iIrq = iIrq;
-            pTask->u.SetIRQ.iLevel = iLevel;
-            pTask->u.SetIRQ.uTagSrc = uTagSrc;
+            pTask->u.IoApicSetIRQ.iIrq = iIrq;
+            pTask->u.IoApicSetIRQ.iLevel = iLevel;
+            pTask->u.IoApicSetIRQ.uTagSrc = uTagSrc;
 
             PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueRC, &pTask->Core, 0);
         }
@@ -964,9 +987,9 @@ static bool pdmRCIsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc)
 
     pTask->enmOp = PDMDEVHLPTASKOP_ISA_SET_IRQ;
     pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
-    pTask->u.SetIRQ.iIrq = iIrq;
-    pTask->u.SetIRQ.iLevel = iLevel;
-    pTask->u.SetIRQ.uTagSrc = uTagSrc;
+    pTask->u.IsaSetIRQ.iIrq = iIrq;
+    pTask->u.IsaSetIRQ.iLevel = iLevel;
+    pTask->u.IsaSetIRQ.uTagSrc = uTagSrc;
 
     PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueRC, &pTask->Core, 0);
     return false;
diff --git a/src/VBox/VMM/include/MMInternal.h b/src/VBox/VMM/include/MMInternal.h
index ab10303..3578b3d 100644
--- a/src/VBox/VMM/include/MMInternal.h
+++ b/src/VBox/VMM/include/MMInternal.h
@@ -673,8 +673,14 @@ typedef struct MMLOOKUPHYPER
         {
             /** The device instance owning the MMIO2 region. */
             PPDMDEVINSR3            pDevIns;
+            /** The sub-device number. */
+            uint32_t                iSubDev;
             /** The region number. */
             uint32_t                iRegion;
+#if HC_ARCH_BITS == 32
+            /** Alignment padding. */
+            uint32_t                uPadding;
+#endif
             /** The offset into the MMIO2 region. */
             RTGCPHYS                off;
         } MMIO2;
diff --git a/src/VBox/VMM/include/PDMInternal.h b/src/VBox/VMM/include/PDMInternal.h
index 30f016a..88fa565 100644
--- a/src/VBox/VMM/include/PDMInternal.h
+++ b/src/VBox/VMM/include/PDMInternal.h
@@ -140,31 +140,23 @@ typedef struct PDMDEVINSINT
 
     /** R3 pointer to the VM this instance was created for. */
     PVMR3                           pVMR3;
-    /** R3 pointer to associated PCI device structure. */
-    R3PTRTYPE(struct PCIDevice *)   pPciDeviceR3;
-    /** R3 pointer to associated PCI bus structure. */
-    R3PTRTYPE(PPDMPCIBUS)           pPciBusR3;
+    /** Associated PCI device list head (first is default). (R3 ptr) */
+    R3PTRTYPE(PPDMPCIDEV)           pHeadPciDevR3;
 
     /** R0 pointer to the VM this instance was created for. */
     PVMR0                           pVMR0;
-    /** R0 pointer to associated PCI device structure. */
-    R0PTRTYPE(struct PCIDevice *)   pPciDeviceR0;
-    /** R0 pointer to associated PCI bus structure. */
-    R0PTRTYPE(PPDMPCIBUS)           pPciBusR0;
+    /** Associated PCI device list head (first is default). (R0 ptr) */
+    R0PTRTYPE(PPDMPCIDEV)           pHeadPciDevR0;
 
     /** RC pointer to the VM this instance was created for. */
     PVMRC                           pVMRC;
-    /** RC pointer to associated PCI device structure. */
-    RCPTRTYPE(struct PCIDevice *)   pPciDeviceRC;
-    /** RC pointer to associated PCI bus structure. */
-    RCPTRTYPE(PPDMPCIBUS)           pPciBusRC;
+    /** Associated PCI device list head (first is default). (RC ptr) */
+    RCPTRTYPE(PPDMPCIDEV)           pHeadPciDevRC;
 
     /** Flags, see PDMDEVINSINT_FLAGS_XXX. */
     uint32_t                        fIntFlags;
     /** The last IRQ tag (for tracing it thru clearing). */
     uint32_t                        uLastIrqTag;
-    /** Size padding. */
-    uint32_t                        u32Padding;
 } PDMDEVINSINT;
 
 /** @name PDMDEVINSINT::fIntFlags
@@ -711,16 +703,17 @@ typedef struct PDMPCIBUS
     /** Pointer to PCI Bus device instance. */
     PPDMDEVINSR3                    pDevInsR3;
     /** @copydoc PDMPCIBUSREG::pfnSetIrqR3 */
-    DECLR3CALLBACKMEMBER(void,      pfnSetIrqR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
+    DECLR3CALLBACKMEMBER(void,      pfnSetIrqR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
     /** @copydoc PDMPCIBUSREG::pfnRegisterR3 */
-    DECLR3CALLBACKMEMBER(int,       pfnRegisterR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev));
+    DECLR3CALLBACKMEMBER(int,       pfnRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
+                                                   uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName));
     /** @copydoc PDMPCIBUSREG::pfnRegisterMsiR3 */
-    DECLR3CALLBACKMEMBER(int,       pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg));
+    DECLR3CALLBACKMEMBER(int,       pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg));
     /** @copydoc PDMPCIBUSREG::pfnIORegionRegisterR3 */
-    DECLR3CALLBACKMEMBER(int,       pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, RTGCPHYS cbRegion,
+    DECLR3CALLBACKMEMBER(int,       pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iRegion, RTGCPHYS cbRegion,
                                                            PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback));
     /** @copydoc PDMPCIBUSREG::pfnSetConfigCallbacksR3 */
-    DECLR3CALLBACKMEMBER(void,      pfnSetConfigCallbacksR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead,
+    DECLR3CALLBACKMEMBER(void,      pfnSetConfigCallbacksR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PFNPCICONFIGREAD pfnRead,
                                                              PPFNPCICONFIGREAD ppfnReadOld, PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld));
     /** @copydoc PDMPCIBUSREG::pfnFakePCIBIOSR3 */
     DECLR3CALLBACKMEMBER(int,       pfnFakePCIBIOSR3,(PPDMDEVINS pDevIns));
@@ -728,12 +721,12 @@ typedef struct PDMPCIBUS
     /** Pointer to the PIC device instance - R0. */
     R0PTRTYPE(PPDMDEVINS)           pDevInsR0;
     /** @copydoc PDMPCIBUSREG::pfnSetIrqR3 */
-    DECLR0CALLBACKMEMBER(void,      pfnSetIrqR0,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
+    DECLR0CALLBACKMEMBER(void,      pfnSetIrqR0,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
 
     /** Pointer to PCI Bus device instance. */
     PPDMDEVINSRC                    pDevInsRC;
     /** @copydoc PDMPCIBUSREG::pfnSetIrqR3 */
-    DECLRCCALLBACKMEMBER(void,      pfnSetIrqRC,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
+    DECLRCCALLBACKMEMBER(void,      pfnSetIrqRC,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc));
 } PDMPCIBUS;
 
 
@@ -990,9 +983,9 @@ typedef struct PDMDEVHLPTASK
     union PDMDEVHLPTASKPARAMS
     {
         /**
-         * PDMDEVHLPTASKOP_ISA_SET_IRQ and PDMDEVHLPTASKOP_PCI_SET_IRQ.
+         * PDMDEVHLPTASKOP_ISA_SET_IRQ and PDMDEVHLPTASKOP_IOAPIC_SET_IRQ.
          */
-        struct PDMDEVHLPTASKSETIRQ
+        struct PDMDEVHLPTASKISASETIRQ
         {
             /** The IRQ */
             int                     iIrq;
@@ -1000,10 +993,25 @@ typedef struct PDMDEVHLPTASK
             int                     iLevel;
             /** The IRQ tag and source. */
             uint32_t                uTagSrc;
-        } SetIRQ;
+        } IsaSetIRQ, IoApicSetIRQ;
+
+        /**
+         * PDMDEVHLPTASKOP_PCI_SET_IRQ
+         */
+        struct PDMDEVHLPTASKPCISETIRQ
+        {
+            /** Pointer to the PCI device (R3 Ptr). */
+            R3PTRTYPE(PPDMPCIDEV)   pPciDevR3;
+            /** The IRQ */
+            int                     iIrq;
+            /** The new level. */
+            int                     iLevel;
+            /** The IRQ tag and source. */
+            uint32_t                uTagSrc;
+        } PciSetIRQ;
 
         /** Expanding the structure. */
-        uint64_t    au64[2];
+        uint64_t    au64[3];
     } u;
 } PDMDEVHLPTASK;
 /** Pointer to a queued Device Helper Task. */
diff --git a/src/VBox/VMM/include/PGMInline.h b/src/VBox/VMM/include/PGMInline.h
index 7a01a25..fbc428a 100644
--- a/src/VBox/VMM/include/PGMInline.h
+++ b/src/VBox/VMM/include/PGMInline.h
@@ -58,7 +58,7 @@ DECLINLINE(PPGMRAMRANGE) pgmPhysGetRange(PVM pVM, RTGCPHYS GCPhys)
 {
     PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
     if (!pRam || GCPhys - pRam->GCPhys >= pRam->cb)
-        pRam = pgmPhysGetRangeSlow(pVM, GCPhys);
+        return pgmPhysGetRangeSlow(pVM, GCPhys);
     STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
     return pRam;
 }
diff --git a/src/VBox/VMM/include/PGMInternal.h b/src/VBox/VMM/include/PGMInternal.h
index 9e8c7bf..1d2e46a 100644
--- a/src/VBox/VMM/include/PGMInternal.h
+++ b/src/VBox/VMM/include/PGMInternal.h
@@ -1538,8 +1538,8 @@ typedef PGMRAMRANGE *PPGMRAMRANGE;
 #define PGM_RAM_RANGE_FLAGS_AD_HOC_ROM      RT_BIT(21)
 /** Ad hoc RAM range for an MMIO mapping. */
 #define PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO     RT_BIT(22)
-/** Ad hoc RAM range for an MMIO2 mapping. */
-#define PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO2    RT_BIT(23)
+/** Ad hoc RAM range for an MMIO2 or pre-registered MMIO mapping. */
+#define PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO_EX  RT_BIT(23)
 /** @} */
 
 /** Tests if a RAM range is an ad hoc one or not.
@@ -1547,7 +1547,7 @@ typedef PGMRAMRANGE *PPGMRAMRANGE;
  * @param   pRam    The RAM range.
  */
 #define PGM_RAM_RANGE_IS_AD_HOC(pRam) \
-    (!!( (pRam)->fFlags & (PGM_RAM_RANGE_FLAGS_AD_HOC_ROM | PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO | PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO2) ) )
+    (!!( (pRam)->fFlags & (PGM_RAM_RANGE_FLAGS_AD_HOC_ROM | PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO | PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO_EX) ) )
 
 /** The number of entries in the RAM range TLBs (there is one for each
  *  context).  Must be a power of two. */
@@ -1687,55 +1687,71 @@ typedef struct PGMLIVESAVEMMIO2PAGE
 typedef PGMLIVESAVEMMIO2PAGE *PPGMLIVESAVEMMIO2PAGE;
 
 /**
- * A registered MMIO2 (= Device RAM) range.
+ * A registered MMIO2 (= Device RAM) or pre-registered MMIO range.
  *
- * There are a few reason why we need to keep track of these
- * registrations.  One of them is the deregistration & cleanup stuff,
- * while another is that the PGMRAMRANGE associated with such a region may
- * have to be removed from the ram range list.
+ * There are a few reason why we need to keep track of these registrations.  One
+ * of them is the deregistration & cleanup stuff, while another is that the
+ * PGMRAMRANGE associated with such a region may have to be removed from the ram
+ * range list.
  *
- * Overlapping with a RAM range has to be 100% or none at all.  The pages
- * in the existing RAM range must not be ROM nor MMIO.  A guru meditation
- * will be raised if a partial overlap or an overlap of ROM pages is
- * encountered.  On an overlap we will free all the existing RAM pages and
- * put in the ram range pages instead.
+ * Overlapping with a RAM range has to be 100% or none at all.  The pages in the
+ * existing RAM range must not be ROM nor MMIO.  A guru meditation will be
+ * raised if a partial overlap or an overlap of ROM pages is encountered.  On an
+ * overlap we will free all the existing RAM pages and put in the ram range
+ * pages instead.
  */
-typedef struct PGMMMIO2RANGE
+typedef struct PGMREGMMIORANGE
 {
     /** The owner of the range. (a device) */
     PPDMDEVINSR3                        pDevInsR3;
-    /** Pointer to the ring-3 mapping of the allocation. */
+    /** Pointer to the ring-3 mapping of the allocation, if MMIO2. */
     RTR3PTR                             pvR3;
     /** Pointer to the next range - R3. */
-    R3PTRTYPE(struct PGMMMIO2RANGE *)   pNextR3;
-    /** Whether it's mapped or not. */
-    bool                                fMapped;
-    /** Whether it's overlapping or not. */
-    bool                                fOverlapping;
-    /** The PCI region number.
-     * @remarks This ASSUMES that nobody will ever really need to have multiple
-     *          PCI devices with matching MMIO region numbers on a single device. */
+    R3PTRTYPE(struct PGMREGMMIORANGE *) pNextR3;
+    /** Flags (PGMREGMMIORANGE_F_XXX). */
+    uint16_t                            fFlags;
+    /** The sub device number (internal PCI config (CFGM) number). */
+    uint8_t                             iSubDev;
+    /** The PCI region number. */
     uint8_t                             iRegion;
     /** The saved state range ID. */
     uint8_t                             idSavedState;
     /** MMIO2 range identifier, for page IDs (PGMPAGE::s.idPage). */
     uint8_t                             idMmio2;
     /** Alignment padding for putting the ram range on a PGMPAGE alignment boundary. */
-    uint8_t                             abAlignment[HC_ARCH_BITS == 32 ? 11 : 11];
-    /** Live save per page tracking data. */
+    uint8_t                             abAlignment[HC_ARCH_BITS == 32 ? 6 : 2];
+    /** Pointer to the physical handler for MMIO. */
+    R3PTRTYPE(PPGMPHYSHANDLER)          pPhysHandlerR3;
+    /** Live save per page tracking data for MMIO2. */
     R3PTRTYPE(PPGMLIVESAVEMMIO2PAGE)    paLSPages;
     /** The associated RAM range. */
     PGMRAMRANGE                         RamRange;
-} PGMMMIO2RANGE;
-/** Pointer to a MMIO2 range. */
-typedef PGMMMIO2RANGE *PPGMMMIO2RANGE;
+} PGMREGMMIORANGE;
+AssertCompileMemberAlignment(PGMREGMMIORANGE, RamRange, 16);
+/** Pointer to a MMIO2 or pre-registered MMIO range. */
+typedef PGMREGMMIORANGE *PPGMREGMMIORANGE;
+
+/** @name PGMREGMMIORANGE_F_XXX - Registered MMIO range flags.
+ * @{ */
+/** Set if it's an MMIO2 range. */
+#define PGMREGMMIORANGE_F_MMIO2             UINT16_C(0x0001)
+/** Set if this is the first chunk in the MMIO2 range. */
+#define PGMREGMMIORANGE_F_FIRST_CHUNK       UINT16_C(0x0002)
+/** Set if this is the last chunk in the MMIO2 range. */
+#define PGMREGMMIORANGE_F_LAST_CHUNK        UINT16_C(0x0004)
+/** Set if the whole range is mapped. */
+#define PGMREGMMIORANGE_F_MAPPED            UINT16_C(0x0008)
+/** Set if it's overlapping, clear if not. */
+#define PGMREGMMIORANGE_F_OVERLAPPING       UINT16_C(0x0010)
+/** @} */
+
 
 /** @name Internal MMIO2 constants.
  * @{ */
 /** The maximum number of MMIO2 ranges. */
 #define PGM_MMIO2_MAX_RANGES                        8
 /** The maximum number of pages in a MMIO2 range. */
-#define PGM_MMIO2_MAX_PAGE_COUNT                    UINT32_C(0x00ffffff)
+#define PGM_MMIO2_MAX_PAGE_COUNT                    UINT32_C(0x01000000)
 /** Makes a MMIO2 page ID out of a MMIO2 range ID and page index number. */
 #define PGM_MMIO2_PAGEID_MAKE(a_idMmio2, a_iPage)   ( ((uint32_t)(a_idMmio2) << 24) | (uint32_t)(a_iPage) )
 /** Gets the MMIO2 range ID from an MMIO2 page ID. */
@@ -3307,13 +3323,13 @@ typedef struct PGM
     R3PTRTYPE(PPGMROMRANGE)         pRomRangesR3;
     /** Pointer to the list of MMIO2 ranges - for R3.
      * Registration order. */
-    R3PTRTYPE(PPGMMMIO2RANGE)       pMmio2RangesR3;
+    R3PTRTYPE(PPGMREGMMIORANGE)     pRegMmioRangesR3;
     /** Pointer to SHW+GST mode data (function pointers).
      * The index into this table is made up from */
     R3PTRTYPE(PPGMMODEDATA)         paModeData;
     RTR3PTR                         R3PtrAlignment0;
     /** MMIO2 lookup array for ring-3.  Indexed by idMmio2 minus 1. */
-    R3PTRTYPE(PPGMMMIO2RANGE)       apMmio2RangesR3[PGM_MMIO2_MAX_RANGES];
+    R3PTRTYPE(PPGMREGMMIORANGE)     apMmio2RangesR3[PGM_MMIO2_MAX_RANGES];
 
     /** RAM range TLB for R0. */
     R0PTRTYPE(PPGMRAMRANGE)         apRamRangesTlbR0[PGM_RAMRANGE_TLB_ENTRIES];
@@ -3333,8 +3349,8 @@ typedef struct PGM
     /** R0 pointer corresponding to PGM::pRomRangesR3. */
     R0PTRTYPE(PPGMROMRANGE)         pRomRangesR0;
     RTR0PTR                         R0PtrAlignment0;
-    /** MMIO2 lookup array for ring-3.  Indexed by idMmio2 minus 1. */
-    R0PTRTYPE(PPGMMMIO2RANGE)       apMmio2RangesR0[PGM_MMIO2_MAX_RANGES];
+    /** MMIO2 lookup array for ring-0.  Indexed by idMmio2 minus 1. */
+    R0PTRTYPE(PPGMREGMMIORANGE)     apMmio2RangesR0[PGM_MMIO2_MAX_RANGES];
 
     /** RAM range TLB for RC. */
     RCPTRTYPE(PPGMRAMRANGE)         apRamRangesTlbRC[PGM_RAMRANGE_TLB_ENTRIES];
@@ -4138,6 +4154,12 @@ int             pgmMapResolveConflicts(PVM pVM);
 PPGMMAPPING     pgmGetMapping(PVM pVM, RTGCPTR GCPtr);
 DECLCALLBACK(void) pgmR3MapInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
 
+int             pgmHandlerPhysicalExCreate(PVM pVM, PGMPHYSHANDLERTYPE hType, RTR3PTR pvUserR3, RTR0PTR pvUserR0,
+                                           RTRCPTR pvUserRC, R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler);
+int             pgmHandlerPhysicalExDup(PVM pVM, PPGMPHYSHANDLER pPhysHandlerSrc, PPGMPHYSHANDLER *ppPhysHandler);
+int             pgmHandlerPhysicalExRegister(PVM pVM, PPGMPHYSHANDLER pPhysHandler, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast);
+int             pgmHandlerPhysicalExDeregister(PVM pVM, PPGMPHYSHANDLER pPhysHandler);
+int             pgmHandlerPhysicalExDestroy(PVM pVM, PPGMPHYSHANDLER pHandler);
 void            pgmR3HandlerPhysicalUpdateAll(PVM pVM);
 bool            pgmHandlerPhysicalIsAll(PVM pVM, RTGCPHYS GCPhys);
 void            pgmHandlerPhysicalResetAliasedPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhysPage, bool fDoAccounting);
diff --git a/src/VBox/VMM/testcase/tstVMStruct.h b/src/VBox/VMM/testcase/tstVMStruct.h
index 74f0a1e..7f4b274 100644
--- a/src/VBox/VMM/testcase/tstVMStruct.h
+++ b/src/VBox/VMM/testcase/tstVMStruct.h
@@ -408,6 +408,10 @@
     GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.HCPhys.pvR3);
     GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.HCPhys.HCPhys);
     GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.GCPhys.GCPhys);
+    GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.MMIO2.pDevIns);
+    GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.MMIO2.iSubDev);
+    GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.MMIO2.iRegion);
+    GEN_CHECK_OFF_DOT(MMLOOKUPHYPER, u.MMIO2.off);
     GEN_CHECK_OFF(MMLOOKUPHYPER, pszDesc);
 
     GEN_CHECK_SIZE(PDM);
@@ -494,19 +498,17 @@
     GEN_CHECK_OFF(PDMDEVINSINT, pNextR3);
     GEN_CHECK_OFF(PDMDEVINSINT, pPerDeviceNextR3);
     GEN_CHECK_OFF(PDMDEVINSINT, pDevR3);
-    GEN_CHECK_OFF(PDMDEVINSINT, pVMR3);
-    GEN_CHECK_OFF(PDMDEVINSINT, pVMR0);
-    GEN_CHECK_OFF(PDMDEVINSINT, pVMRC);
     GEN_CHECK_OFF(PDMDEVINSINT, pLunsR3);
     GEN_CHECK_OFF(PDMDEVINSINT, pfnAsyncNotify);
     GEN_CHECK_OFF(PDMDEVINSINT, pCfgHandle);
-    GEN_CHECK_OFF(PDMDEVINSINT, pPciDeviceR3);
-    GEN_CHECK_OFF(PDMDEVINSINT, pPciDeviceR0);
-    GEN_CHECK_OFF(PDMDEVINSINT, pPciDeviceRC);
-    GEN_CHECK_OFF(PDMDEVINSINT, pPciBusR3);
-    GEN_CHECK_OFF(PDMDEVINSINT, pPciBusR0);
-    GEN_CHECK_OFF(PDMDEVINSINT, pPciBusRC);
+    GEN_CHECK_OFF(PDMDEVINSINT, pVMR3);
+    GEN_CHECK_OFF(PDMDEVINSINT, pVMR0);
+    GEN_CHECK_OFF(PDMDEVINSINT, pVMRC);
+    GEN_CHECK_OFF(PDMDEVINSINT, pHeadPciDevR3);
+    GEN_CHECK_OFF(PDMDEVINSINT, pHeadPciDevR0);
+    GEN_CHECK_OFF(PDMDEVINSINT, pHeadPciDevRC);
     GEN_CHECK_OFF(PDMDEVINSINT, fIntFlags);
+    GEN_CHECK_OFF(PDMDEVINSINT, uLastIrqTag);
     GEN_CHECK_OFF(PDMDEVINS, u32Version);
     GEN_CHECK_OFF(PDMDEVINS, iInstance);
     GEN_CHECK_OFF(PDMDEVINS, pHlpRC);
@@ -609,8 +611,16 @@
     GEN_CHECK_OFF(PDMDEVHLPTASK, pDevInsR3);
     GEN_CHECK_OFF(PDMDEVHLPTASK, enmOp);
     GEN_CHECK_OFF(PDMDEVHLPTASK, u);
-    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.SetIRQ.iIrq);
-    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.SetIRQ.iLevel);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.IsaSetIRQ.iIrq);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.IsaSetIRQ.iLevel);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.IsaSetIRQ.uTagSrc);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.IoApicSetIRQ.iIrq);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.IoApicSetIRQ.iLevel);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.IoApicSetIRQ.uTagSrc);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.PciSetIRQ.pPciDevR3);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.PciSetIRQ.iIrq);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.PciSetIRQ.iLevel);
+    GEN_CHECK_OFF_DOT(PDMDEVHLPTASK, u.PciSetIRQ.uTagSrc);
 
     GEN_CHECK_SIZE(PGM);
     GEN_CHECK_OFF(PGM, offVM);
@@ -877,13 +887,13 @@
     GEN_CHECK_OFF(PGMROMRANGE, pszDesc);
     GEN_CHECK_OFF(PGMROMRANGE, aPages);
     GEN_CHECK_OFF(PGMROMRANGE, aPages[1]);
-    GEN_CHECK_SIZE(PGMMMIO2RANGE);
-    GEN_CHECK_OFF(PGMMMIO2RANGE, pDevInsR3);
-    GEN_CHECK_OFF(PGMMMIO2RANGE, pNextR3);
-    GEN_CHECK_OFF(PGMMMIO2RANGE, fMapped);
-    GEN_CHECK_OFF(PGMMMIO2RANGE, fOverlapping);
-    GEN_CHECK_OFF(PGMMMIO2RANGE, iRegion);
-    GEN_CHECK_OFF(PGMMMIO2RANGE, RamRange);
+    GEN_CHECK_SIZE(PGMREGMMIORANGE);
+    GEN_CHECK_OFF(PGMREGMMIORANGE, pDevInsR3);
+    GEN_CHECK_OFF(PGMREGMMIORANGE, pNextR3);
+    GEN_CHECK_OFF(PGMREGMMIORANGE, fFlags);
+    GEN_CHECK_OFF(PGMREGMMIORANGE, iRegion);
+    GEN_CHECK_OFF(PGMREGMMIORANGE, pPhysHandlerR3);
+    GEN_CHECK_OFF(PGMREGMMIORANGE, RamRange);
     GEN_CHECK_SIZE(PGMTREES);
     GEN_CHECK_OFF(PGMTREES, PhysHandlers);
     GEN_CHECK_OFF(PGMTREES, HeadPhysHandlerTypes);
diff --git a/src/VBox/VMM/testcase/tstVMStructSize.cpp b/src/VBox/VMM/testcase/tstVMStructSize.cpp
index c06296e..13ec0f2 100644
--- a/src/VBox/VMM/testcase/tstVMStructSize.cpp
+++ b/src/VBox/VMM/testcase/tstVMStructSize.cpp
@@ -384,7 +384,7 @@ int main()
     CHECK_MEMBER_ALIGNMENT(PGMPOOLPAGE, GCPhys, sizeof(RTGCPHYS));
     CHECK_SIZE(PGMPAGE, 16);
     CHECK_MEMBER_ALIGNMENT(PGMRAMRANGE, aPages, 16);
-    CHECK_MEMBER_ALIGNMENT(PGMMMIO2RANGE, RamRange, 16);
+    CHECK_MEMBER_ALIGNMENT(PGMREGMMIORANGE, RamRange, 16);
 
     /* rem */
     CHECK_MEMBER_ALIGNMENT(REM, aGCPtrInvalidatedPages, 8);
diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac
index 090ccf4..3c6a073 100644
--- a/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac
+++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac
@@ -124,7 +124,7 @@ g_aTrapRecsEnd:
 ;;
 ; Macro for installing the trap records.
 ;
-; This must be invoked prior the the traps.
+; This must be invoked prior to the traps.
 ;
 ; @uses Stack
 ;
diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c
index c6e3f49..dd1ac50 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c
+++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c
@@ -676,7 +676,7 @@ BS3_DECL_NEAR(void) bs3CpuBasic2_RaiseXcpt1Common(uint16_t const uSysR0Cs, uint1
                     paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
                     g_usBs3TestStep++;
 
-                    /* +2: Check the the CS.DPL check is done before the SS ones. Restoring the
+                    /* +2: Check the CS.DPL check is done before the SS ones. Restoring the
                            ring-0 INT 83 context triggers the CS.DPL < CPL check. */
                     Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx);
                     bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02);
diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c
index d10d8f9..ba1cb47 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c
+++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c
@@ -797,7 +797,7 @@ static void bs3CpuBasic2_RaiseXcpt1Common(uint16_t const uSysR0Cs, uint16_t cons
                     paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
                     g_usBs3TestStep++;
 
-                    /* +2: Check the the CS.DPL check is done before the SS ones. Restoring the
+                    /* +2: Check the CS.DPL check is done before the SS ones. Restoring the
                            ring-0 INT 83 context triggers the CS.DPL < CPL check. */
                     Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx);
                     bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02);
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
index 74d0475..8a788a7 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
@@ -158,7 +158,7 @@ CPU 386
 .stack_fine:
         movzx   esp, sp
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     bx, (BS3TRAPFRAME_size + 7) / 8
 .more_zeroed_space:
         push    0
@@ -215,7 +215,7 @@ CPU 286
         pushf
         cld
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     bx, (BS3TRAPFRAME_size + 7) / 8
 .more_zeroed_space:
         push    0
@@ -527,7 +527,7 @@ CPU 386
         mov     bp, sp
         pushfd                          ; Handler flags.
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     bx, (BS3TRAPFRAME_size + 15) / 16
 .more_zeroed_space:
         push    dword 0
@@ -676,7 +676,7 @@ CPU 286
         mov     bp, sp
         pushf                           ; Handler flags.
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     bx, (BS3TRAPFRAME_size + 7) / 8
 .more_zeroed_space:
         push    0
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm
index 387495b..f269340 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm
@@ -125,7 +125,7 @@ CPU 386
         push    ss                      ; BP - 0eh
         push    esp                     ; BP - 12h
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     bx, (BS3TRAPFRAME_size + 7) / 8
 .more_zeroed_space:
         push    0
@@ -181,7 +181,7 @@ CPU 8086
         push    ax                      ; BP - 6
         cld
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     bx, (BS3TRAPFRAME_size + 7) / 8
         xor     ax, ax
 .more_zeroed_space:
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm
index a8eb14a..14028fa 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm
@@ -186,7 +186,7 @@ BS3_PROC_BEGIN bs3Trap32GenericTrapOrInt
         add     word [ebp - 10h],  (4+1+3)*4
 .stack_flat:
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     eax, (BS3TRAPFRAME_size + 7) / 8
 AssertCompileSizeAlignment(BS3TRAPFRAME, 8)
 .more_zeroed_space:
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm
index 0231fe0..be8d576 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm
@@ -118,7 +118,7 @@ BS3_PROC_BEGIN Bs3Trap64GenericTrapOrInt
         cld
         push    rdi
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     edi, (BS3TRAPFRAME_size + 15) / 16
 .more_zeroed_space:
         push    qword 0
@@ -155,7 +155,7 @@ BS3_PROC_BEGIN Bs3Trap64GenericTrapErrCode
         cld
         push    rdi
 
-        ; Reserve space for the the register and trap frame.
+        ; Reserve space for the register and trap frame.
         mov     edi, (BS3TRAPFRAME_size + 15) / 16
 .more_zeroed_space:
         push    qword 0
diff --git a/src/VBox/ValidationKit/testanalysis/diff.py b/src/VBox/ValidationKit/testanalysis/diff.py
index 423531a..4115b9a 100755
--- a/src/VBox/ValidationKit/testanalysis/diff.py
+++ b/src/VBox/ValidationKit/testanalysis/diff.py
@@ -26,12 +26,12 @@ CDDL are applicable instead of those of the GPL.
 You may elect to license modified versions of this file under the
 terms and conditions of either the GPL or the CDDL or both.
 """
-__version__ = "$Revision: 109040 $"
+__version__ = "$Revision: 111712 $"
 __all__     = ['BaselineDiff', ];
 
 
 def _findBaselineTest(oBaseline, oTest):
-    """ Recursively finds the the test in oBaseline corresponding to oTest. """
+    """ Recursively finds the test in oBaseline corresponding to oTest. """
     if oTest.oParent is None:
         return oBaseline;
     oBaseline = _findBaselineTest(oBaseline, oTest.oParent);
diff --git a/src/VBox/ValidationKit/testanalysis/reporting.py b/src/VBox/ValidationKit/testanalysis/reporting.py
index fe0280c..cbb37c4 100755
--- a/src/VBox/ValidationKit/testanalysis/reporting.py
+++ b/src/VBox/ValidationKit/testanalysis/reporting.py
@@ -29,7 +29,7 @@ CDDL are applicable instead of those of the GPL.
 You may elect to license modified versions of this file under the
 terms and conditions of either the GPL or the CDDL or both.
 """
-__version__ = "$Revision: 109040 $"
+__version__ = "$Revision: 111712 $"
 __all__     = ['HtmlReport', 'RstReport', 'TextReport'];
 
 
@@ -238,7 +238,7 @@ def produceTextReport(oTest):
     ## @todo later
 
     #
-    # Tabelize the the results and display the tables.
+    # Tabelize the results and display the tables.
     #
     aoTables = tabelizeTestResults(oTest, True)
     for oTable in aoTables:
diff --git a/src/VBox/ValidationKit/testmanager/webui/wuimain.py b/src/VBox/ValidationKit/testmanager/webui/wuimain.py
index 42112ab..2ec93d4 100755
--- a/src/VBox/ValidationKit/testmanager/webui/wuimain.py
+++ b/src/VBox/ValidationKit/testmanager/webui/wuimain.py
@@ -26,7 +26,7 @@ CDDL are applicable instead of those of the GPL.
 You may elect to license modified versions of this file under the
 terms and conditions of either the GPL or the CDDL or both.
 """
-__version__ = "$Revision: 109040 $"
+__version__ = "$Revision: 111712 $"
 
 # Standard Python imports.
 
@@ -733,7 +733,7 @@ class WuiMain(WuiDispatcherBase):
         #
         # Fetch the group members.
         #
-        # If no grouping is selected, we'll fill the the grouping combo with
+        # If no grouping is selected, we'll fill the grouping combo with
         # testboxes just to avoid having completely useless combo box.
         #
         oTrLogic = TestResultLogic(self._oDb);
diff --git a/src/bldprogs/scmstream.h b/src/bldprogs/scmstream.h
index 96241f6..ac7252a 100644
--- a/src/bldprogs/scmstream.h
+++ b/src/bldprogs/scmstream.h
@@ -69,7 +69,7 @@ typedef struct SCMSTREAM
     size_t          iLine;
     /** The current stream size given in lines.   */
     size_t          cLines;
-    /** The sizeof the the memory backing paLines.   */
+    /** The sizeof the memory backing paLines.   */
     size_t          cLinesAllocated;
 
     /** Set if write-only, clear if read-only. */
diff --git a/src/libs/Makefile.kmk b/src/libs/Makefile.kmk
index f3bcdcc..9759984 100644
--- a/src/libs/Makefile.kmk
+++ b/src/libs/Makefile.kmk
@@ -52,7 +52,7 @@ endif
 if !defined(VBOX_ONLY_SDK) \
  && (   "$(SDK_VBOX_OPENSSL_INCS)" == "$(SDK_VBOX_OPENSSL_VBOX_DEFAULT_INCS)" \
      || defined(VBOX_WITH_EXTPACK_PUEL_BUILD))
- include $(PATH_SUB_CURRENT)/openssl-1.1.0b/Makefile.kmk
+ include $(PATH_SUB_CURRENT)/openssl-1.1.0c/Makefile.kmk
 endif
 
 # libjpeg for VRDP video redirection and ExtPack's DrvHostWebcam
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp
index 52eb21f..5cd7a0c 100644
--- a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp
@@ -419,7 +419,9 @@ TryConnect(PRFileDesc **result)
   PRFileDesc *fd;
   PRNetAddr addr;
   PRSocketOptionData opt;
-  nsresult rv = NS_ERROR_FAILURE;
+  // don't use NS_ERROR_FAILURE as we want to detect these kind of errors
+  // in the frontend
+  nsresult rv = NS_ERROR_SOCKET_FAIL;
 
   fd = PR_OpenTCPSocket(PR_AF_LOCAL);
   if (!fd)
@@ -479,7 +481,9 @@ IPC_Connect(const char *daemonPath)
   rv = TryConnect(&fd);
   if (NS_FAILED(rv))
   {
-    rv = IPC_SpawnDaemon(daemonPath);
+    nsresult rv1 = IPC_SpawnDaemon(daemonPath);
+    if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL)
+      rv = rv1; 
     if (NS_SUCCEEDED(rv))
       rv = TryConnect(&fd);
   }
diff --git a/src/libs/xpcom18a4/python/src/PyIID.cpp b/src/libs/xpcom18a4/python/src/PyIID.cpp
index 459bd3c..33c2547 100644
--- a/src/libs/xpcom18a4/python/src/PyIID.cpp
+++ b/src/libs/xpcom18a4/python/src/PyIID.cpp
@@ -318,12 +318,21 @@ Py_nsIID::PyTypeMethod_str(PyObject *self)
 	return ret;
 }
 
+#if PY_VERSION_HEX >= 0x03020000
+/* static */Py_hash_t
+Py_nsIID::PyTypeMethod_hash(PyObject *self)
+#else
 /* static */long
 Py_nsIID::PyTypeMethod_hash(PyObject *self)
+#endif
 {
 	const nsIID &iid = ((Py_nsIID *)self)->m_iid;
 
+#if PY_VERSION_HEX >= 0x03020000
+	Py_hash_t ret = iid.m0 + iid.m1 + iid.m2;
+#else
 	long ret = iid.m0 + iid.m1 + iid.m2;
+#endif
 	for (int i=0;i<7;i++)
 		ret += iid.m3[i];
 	if ( ret == -1 )
diff --git a/src/libs/xpcom18a4/python/src/PyXPCOM.h b/src/libs/xpcom18a4/python/src/PyXPCOM.h
index 935baad..368b002 100644
--- a/src/libs/xpcom18a4/python/src/PyXPCOM.h
+++ b/src/libs/xpcom18a4/python/src/PyXPCOM.h
@@ -286,7 +286,11 @@ public:
 	static int Py_setattr(PyObject *op, char *name, PyObject *v);
 	static int Py_cmp(PyObject *ob1, PyObject *ob2);
 	static PyObject *Py_richcmp(PyObject *ob1, PyObject *ob2, int op);
+#if PY_VERSION_HEX >= 0x03020000
+	static Py_hash_t Py_hash(PyObject *self);
+#else
 	static long Py_hash(PyObject *self);
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -442,7 +446,11 @@ public:
 #endif
 	static PyObject *PyTypeMethod_richcompare(PyObject *self, PyObject *ob, int op);
 	static PyObject *PyTypeMethod_repr(PyObject *self);
+#if PY_VERSION_HEX >= 0x03020000
+	static Py_hash_t PyTypeMethod_hash(PyObject *self);
+#else
 	static long PyTypeMethod_hash(PyObject *self);
+#endif
 	static PyObject *PyTypeMethod_str(PyObject *self);
 	static void PyTypeMethod_dealloc(PyObject *self);
 	static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type;
diff --git a/src/libs/xpcom18a4/python/src/TypeObject.cpp b/src/libs/xpcom18a4/python/src/TypeObject.cpp
index 3a1f949..10b4093 100644
--- a/src/libs/xpcom18a4/python/src/TypeObject.cpp
+++ b/src/libs/xpcom18a4/python/src/TypeObject.cpp
@@ -155,13 +155,21 @@ PyXPCOM_TypeObject::Py_richcmp(PyObject *self, PyObject *other, int op)
 }
 
 // @pymethod int|Py_nsISupports|__hash__|Implement a hash-code for the XPCOM object using XPCOM identity rules.
+#if PY_VERSION_HEX >= 0x03020000
+/*static*/Py_hash_t PyXPCOM_TypeObject::Py_hash(PyObject *self)
+#else
 /*static*/long PyXPCOM_TypeObject::Py_hash(PyObject *self)
+#endif
 {
 	// We always return the value of the nsISupports *.
 	nsISupports *pUnkThis;
 	if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE))
 		return -1;
+#if PY_VERSION_HEX >= 0x03020000
+	Py_hash_t ret = _Py_HashPointer(pUnkThis);
+#else
 	long ret = _Py_HashPointer(pUnkThis);
+#endif
 	pUnkThis->Release();
 	return ret;
 }
diff --git a/src/libs/xpcom18a4/xpcom/base/nsError.h b/src/libs/xpcom18a4/xpcom/base/nsError.h
index 79074bd..e0f3fe5 100644
--- a/src/libs/xpcom18a4/xpcom/base/nsError.h
+++ b/src/libs/xpcom18a4/xpcom/base/nsError.h
@@ -214,6 +214,9 @@
 /* Returned when a factory already is registered */
 #define NS_ERROR_FACTORY_EXISTS            (NS_ERROR_BASE + 0x100)
 
+/* Socket failures */
+#define NS_ERROR_SOCKET_FAIL               (NS_ERROR_BASE + 0x200)
+
 
 /* For COM compatibility reasons, we want to use exact error code numbers
    for NS_ERROR_PROXY_INVALID_IN_PARAMETER and NS_ERROR_PROXY_INVALID_OUT_PARAMETER.
diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp
index ec3cb3f..980b056 100644
--- a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp
+++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp
@@ -1961,7 +1961,8 @@ nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
     else
     {
         // Translate error values
-        rv = NS_ERROR_FACTORY_NOT_REGISTERED;
+        if (rv != NS_ERROR_SOCKET_FAIL)
+            rv = NS_ERROR_FACTORY_NOT_REGISTERED;
     }
 
     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
diff --git a/src/recompiler/VBoxRecompiler.c b/src/recompiler/VBoxRecompiler.c
index 9fb4990..6a85cc5 100644
--- a/src/recompiler/VBoxRecompiler.c
+++ b/src/recompiler/VBoxRecompiler.c
@@ -2555,7 +2555,7 @@ REMR3DECL(int)  REMR3State(PVM pVM, PVMCPU pVCpu)
 
 
 /**
- * Syncs back changes in the REM state to the the VM state.
+ * Syncs back changes in the REM state to the VM state.
  *
  * This must be called after invoking REMR3Run().
  * Calling it several times in a row is not permitted.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/virtualbox.git



More information about the Pkg-virtualbox-commits mailing list