[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(&LIFIER_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: %2</nobr><br><nobr>Type: %3</nobr></source>
- <translation><nobr><b>%1</b></nobr><br><nobr>Δίαυλος: %2</nobr><br><nobr>Τύπος: %3</nobr></translation>
+ <translation><nobr><b>%1</b></nobr><br><nobr>Ελεγκτής: %2</nobr><br><nobr>Τύπος: %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 Item</nobr></source>
- <translation type="obsolete"><nobr>Öğeyi Genişlet/Daralt</nobr></translation>
+ <translation type="obsolete"><nobr>Ögeyi Genişlet/Daralt</nobr></translation>
</message>
<message>
<source><nobr>Add Hard 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 item.</nobr></source>
- <translation><nobr>Öğeyi Genişletir/Daraltır.</nobr></translation>
+ <translation><nobr>Ögeyi Genişletir/Daraltır.</nobr></translation>
</message>
<message>
<source><nobr>Adds hard 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 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: </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ı: </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ı: </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: </b></td><td>%2</td></tr><tr><td><b>New Version: </b></td><td>%3</td></tr><tr><td><b>Current Version: </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