Index: /trunk/include/VBox/vmm/pdmaudioifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 60352)
+++ /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 60353)
@@ -109,14 +109,70 @@
 } PDMAUDIOENDIANNESS;
 
+/**
+ * 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 playback destinations.
+ */
+typedef enum PDMAUDIOPLAYBACKDEST
+{
+    PDMAUDIOPLAYBACKDEST_UNKNOWN = 0,
+    PDMAUDIOPLAYBACKDEST_FRONT,
+    PDMAUDIOPLAYBACKDEST_CENTER_LFE,
+    PDMAUDIOPLAYBACKDEST_REAR,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIOPLAYBACKDEST_32BIT_HACK = 0x7fffffff
+} PDMAUDIOPLAYBACKDEST;
+
+/**
+ * Audio recording sources.
+ */
+typedef enum PDMAUDIORECSOURCE
+{
+    PDMAUDIORECSOURCE_UNKNOWN = 0,
+    PDMAUDIORECSOURCE_MIC,
+    PDMAUDIORECSOURCE_CD,
+    PDMAUDIORECSOURCE_VIDEO,
+    PDMAUDIORECSOURCE_AUX,
+    PDMAUDIORECSOURCE_LINE,
+    PDMAUDIORECSOURCE_PHONE,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIORECSOURCE_32BIT_HACK = 0x7fffffff
+} PDMAUDIORECSOURCE;
+
+/**
+ * Structure for keeping an audio stream configuration.
+ */
 typedef struct PDMAUDIOSTREAMCFG
 {
+    /** Friendly name of the stream. */
+    char                    *pszName;
+    /** Direction of the stream. */
+    PDMAUDIODIR              enmDir;
+    union
+    {
+        /** Desired playback destination (for an output stream). */
+        PDMAUDIOPLAYBACKDEST Dest;
+        /** Desired recording source (for an input stream). */
+        PDMAUDIORECSOURCE    Source;
+    } DestSource;
     /** Frequency in Hertz (Hz). */
-    uint32_t uHz;
-    /** Number of channels (2 for stereo). */
-    uint8_t cChannels;
+    uint32_t                 uHz;
+    /** Number of channels (2 for stereo, 1 for mono). */
+    uint8_t                  cChannels;
     /** Audio format. */
-    PDMAUDIOFMT enmFormat;
+    PDMAUDIOFMT              enmFormat;
     /** @todo Use RT_LE2H_*? */
-    PDMAUDIOENDIANNESS enmEndianness;
+    PDMAUDIOENDIANNESS       enmEndianness;
 } PDMAUDIOSTREAMCFG, *PPDMAUDIOSTREAMCFG;
 
@@ -130,17 +186,4 @@
 
 /**
- * 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.
  */
@@ -149,5 +192,7 @@
     PDMAUDIOMIXERCTL_UNKNOWN = 0,
     PDMAUDIOMIXERCTL_VOLUME,
-    PDMAUDIOMIXERCTL_PCM,
+    PDMAUDIOMIXERCTL_FRONT,
+    PDMAUDIOMIXERCTL_CENTER_LFE,
+    PDMAUDIOMIXERCTL_REAR,
     PDMAUDIOMIXERCTL_LINE_IN,
     PDMAUDIOMIXERCTL_MIC_IN,
@@ -155,20 +200,4 @@
     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;
 
 /**
@@ -586,12 +615,10 @@
      * @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   pszName              Friendly name of this input stream.
      * @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));
+                                            PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMIN *ppGstStrmIn));
     /**
      * Creates a guest output stream.
@@ -599,5 +626,5 @@
      * @returns VBox status code.
      * @param   pInterface           Pointer to the interface structure containing the called function pointer.
-     * @param   pszName              Name of the audio channel.
+     * @param   pszName              Friendly name of this output stream.
      * @param   pCfg                 Pointer to PDMAUDIOSTREAMCFG to use.
      * @param   ppGstStrmOut         Pointer where to return the guest guest input stream on success.
@@ -639,5 +666,5 @@
 
 /** PDMIAUDIOCONNECTOR interface ID. */
-#define PDMIAUDIOCONNECTOR_IID                  "8f8ca10e-9039-423c-9a77-0014aaa98626"
+#define PDMIAUDIOCONNECTOR_IID                  "f0ef4012-ae89-4528-9dad-4ef496894df8"
 
 
Index: /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 60353)
@@ -6,5 +6,5 @@
 
 /*
- * Copyright (C) 2014-2015 Oracle Corporation
+ * Copyright (C) 2014-2016 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -19,4 +19,5 @@
 #include <VBox/log.h>
 
+#if 0
 /*
  * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
@@ -24,12 +25,17 @@
  * to your needs before using this!
  */
-#ifdef DEBUG
-//# define DEBUG_DUMP_PCM_DATA
-# define DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
+# ifdef RT_OS_WINDOWS
+#  define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# else
+#  define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+# endif
+/* Warning: Enabling this will generate *huge* logs! */
+//# define AUDIOMIXBUF_DEBUG_MACROS
 #endif
 
 #include <iprt/asm-math.h>
 #include <iprt/assert.h>
-#ifdef DEBUG_DUMP_PCM_DATA
+#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
 # include <iprt/file.h>
 #endif
@@ -37,5 +43,5 @@
 #include <iprt/string.h> /* For RT_BZERO. */
 
-#ifdef TESTCASE
+#ifdef VBOX_AUDIO_TESTCASE
 # define LOG_ENABLED
 # include <iprt/stream.h>
@@ -45,12 +51,12 @@
 #include "AudioMixBuffer.h"
 
-#if 0
-# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
-#else
-# if defined(TESTCASE)
-#  define AUDMIXBUF_LOG(x) LogFunc(x)
+#ifndef VBOX_AUDIO_TESTCASE
+# ifdef DEBUG
+#  define AUDMIXBUF_LOG(x) LogFlowFunc(x)
 # else
-#  define AUDMIXBUF_LOG(x) do {} while (0)
+# define AUDMIXBUF_LOG(x) do {} while (0)
 # endif
+#else /* VBOX_AUDIO_TESTCASE */
+# define AUDMIXBUF_LOG(x) RTPrintf x
 #endif
 
@@ -144,5 +150,5 @@
  * inlined + static.
  */
-#ifdef TESTCASE
+#ifdef VBOX_AUDIO_TESTCASE
 # define AUDMIXBUF_MACRO_FN
 #else
@@ -404,10 +410,7 @@
 }
 
-/** Note: Enabling this will generate huge logs! */
-//#define DEBUG_MACROS
-
-#ifdef DEBUG_MACROS
+#ifdef AUDIOMIXBUF_DEBUG_MACROS
 # define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
-#elif defined(TESTCASE)
+#elif defined(VBOX_AUDIO_TESTCASE_VERBOSE) /* Warning: VBOX_AUDIO_TESTCASE_VERBOSE will generate huge logs! */
 # define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
 #else
@@ -449,12 +452,12 @@
         _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", \
+        AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%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))); \
+            AUDMIXBUF_MACRO_LOG(("l=%#5RI16 (0x%x), r=%#5RI16 (0x%x)", paDst, *pSrc, *pSrc, *(pSrc + 1), *(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)); \
+            AUDMIXBUF_MACRO_LOG((" -> l=%#10RI64, r=%#10RI64\n", paDst->i64LSample, paDst->i64RSample)); \
             paDst++; \
         } \
@@ -467,14 +470,13 @@
     { \
         _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)); \
+        const uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
+        AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
+                             cSamples, sizeof(_aType), pOpts->Volume.uLeft >> 14, 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)); \
+            AUDMIXBUF_MACRO_LOG(("%#5RI16 (0x%x) -> l=%#10RI64, r=%#10RI64\n", *pSrc, *pSrc, paDst->i64LSample, paDst->i64RSample)); \
+            pSrc++; \
             paDst++; \
         } \
@@ -537,8 +539,7 @@
     { \
         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)); \
+        AUDMIXBUF_MACRO_LOG(("Rate: srcOffset=%RU32, dstOffset=%RU32, dstInc=%RU32\n", \
+                             pRate->srcOffset, \
+                             (uint32_t)(pRate->dstOffset >> 32), (uint32_t)(pRate->dstInc >> 32))); \
         \
         if (pRate->dstInc == (UINT64_C(1) + UINT32_MAX)) /* No conversion needed? */ \
@@ -563,11 +564,7 @@
         PPDMAUDIOSAMPLE paDstStart = paDst; \
         PPDMAUDIOSAMPLE paDstEnd   = paDst + cDstSamples; \
-        PDMAUDIOSAMPLE  samCur = { 0 }; \
+        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) \
@@ -575,8 +572,7 @@
             Assert(paSrc <= paSrcEnd); \
             Assert(paDst <= paDstEnd); \
-            if (paSrc == paSrcEnd) \
+            if (paSrc >= paSrcEnd) \
                 break; \
             \
-            lDelta = 0; \
             while (pRate->srcOffset <= (pRate->dstOffset >> 32)) \
             { \
@@ -584,5 +580,4 @@
                 samLast = *paSrc++; \
                 pRate->srcOffset++; \
-                lDelta++; \
                 if (paSrc == paSrcEnd) \
                     break; \
@@ -604,23 +599,22 @@
             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)); \
+            AUDMIXBUF_MACRO_LOG(("\tiDstOffInt=%RI64, l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64)\n", \
+                                 iDstOffInt, \
+                                 paDst->i64LSample >> 32, paDst->i64RSample >> 32, \
+                                 samCur.i64LSample >> 32, samCur.i64RSample >> 32)); \
             \
             paDst++; \
             pRate->dstOffset += pRate->dstInc; \
             \
-            AUDMIXBUF_MACRO_LOG(("\t\tpRate->dstOffset=0x%RX32 (%RU32)\n", pRate->dstOffset, pRate->dstOffset >> 32)); \
+            AUDMIXBUF_MACRO_LOG(("\t\tpRate->dstOffset=%RU32\n", 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)); \
+        AUDMIXBUF_MACRO_LOG(("%zu source samples -> %zu dest samples\n", paSrc - paSrcStart, paDst - paDstStart)); \
         \
         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)); \
+        AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64\n", \
+                              pRate->srcSampleLast.i64LSample, pRate->srcSampleLast.i64RSample)); \
         \
         if (pcDstWritten) \
@@ -643,5 +637,5 @@
 {
     /* Internally zero always corresponds to silence. */
-    memset(paDst, 0, pOpts->cSamples * sizeof(paDst[0]));
+    RT_BZERO(paDst, pOpts->cSamples * sizeof(paDst[0]));
     return pOpts->cSamples;
 }
@@ -674,5 +668,5 @@
             }
         }
-        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        else
         {
             switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
@@ -697,5 +691,5 @@
             }
         }
-        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        else
         {
             switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
@@ -735,5 +729,5 @@
             }
         }
-        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        else
         {
             switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
@@ -758,5 +752,5 @@
             }
         }
-        else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
+        else
         {
             switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
@@ -856,5 +850,5 @@
  *
  * The audio format of each mixing buffer can vary; the internal mixing code
- * then will autiomatically do the (needed) conversion.
+ * then will automatically do the (needed) conversion.
  *
  * @return  IPRT status code.
@@ -996,15 +990,18 @@
      * 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 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 offWrite      = (pDst->offReadWrite + cLive) % pDst->cSamples;
+
+    AUDMIXBUF_LOG(("pSrc=%s (%RU32 samples, %RU8 chan), pDst=%s (%RU32 samples, %RU8 chan), " \
+                   "cLive=%RU32, cDead=%RU32, cToReadTotal=%RU32, offWrite=%RU32\n",
+                   pSrc->pszName, pSrc->cSamples, AUDMIXBUF_FMT_CHANNELS(pSrc->AudioFmt),
+                   pDst->pszName, pDst->cSamples, AUDMIXBUF_FMT_CHANNELS(pDst->AudioFmt),
+                   cLive, cDead, cToReadTotal, offWrite));
 
     uint32_t cToRead, cToWrite;
@@ -1030,7 +1027,7 @@
                        cDead, offWrite, cToWrite, offRead, cToRead));
 
-        audioMixBufOpBlend(pDst->pSamples + offWrite, cToWrite,
-                           pSrc->pSamples + offRead, cToRead,
-                           pSrc->pRate, &cWritten, &cRead);
+        audioMixBufOpAssign(pDst->pSamples + offWrite, cToWrite,
+                            pSrc->pSamples + offRead, cToRead,
+                            pSrc->pRate, &cWritten, &cRead);
 
         AUDMIXBUF_LOG(("\t\tcWritten=%RU32, cRead=%RU32\n", cWritten, cRead));
@@ -1138,5 +1135,5 @@
 
     AUDMIXBUF_LOG(("********************************************\n"));
-    AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
+    AUDMIXBUF_LOG(("[PARENT] %s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
                    pParent->pszName,
                    pParent->offReadWrite, pParent->cProcessed, pParent->cMixed,
@@ -1146,5 +1143,5 @@
     RTListForEach(&pParent->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
     {
-        AUDMIXBUF_LOG(("\t%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
+        AUDMIXBUF_LOG(("\t[CHILD] %s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
                        pIter->pszName,
                        pIter->offReadWrite, pIter->cProcessed, pIter->cMixed,
@@ -1363,7 +1360,7 @@
     if (RT_SUCCESS(rc))
     {
-#ifdef DEBUG_DUMP_PCM_DATA
+#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
         RTFILE fh;
-        rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
+        rc = RTFileOpen(&fh, AUDIOMIXBUF_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))
@@ -1507,5 +1504,4 @@
  * @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.
@@ -1513,8 +1509,5 @@
  * @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)
+int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
 {
     return AudioMixBufWriteAtEx(pMixBuf, pMixBuf->AudioFmt,
@@ -1565,7 +1558,7 @@
     uint32_t cWritten;
 
-#ifdef DEBUG_DUMP_PCM_DATA
+#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
     RTFILE fh;
-    rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
+    rc = RTFileOpen(&fh, AUDIOMIXBUF_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))
@@ -1718,7 +1711,7 @@
     }
 
-#ifdef DEBUG_DUMP_PCM_DATA
+#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
         RTFILE fh;
-        RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeex.pcm",
+        RTFileOpen(&fh, AUDIOMIXBUF_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);
Index: /trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 60353)
@@ -310,5 +310,4 @@
     RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     {
-        /** @todo Support output sinks as well! */
         if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->pIn))
             continue;
@@ -327,4 +326,6 @@
                 break;
 
+            /** @todo Right now we only handle one stream (the last one added in fact). */
+
             AssertBreakStmt(cbRead <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
             cbToRead -= cbRead;
Index: /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 60353)
@@ -616,5 +616,5 @@
             pSink = pThis->pSinkMicIn;
             break;
-        case PDMAUDIORECSOURCE_LINE_IN:
+        case PDMAUDIORECSOURCE_LINE:
             pSink = pThis->pSinkLineIn;
             break;
@@ -642,8 +642,7 @@
             pStrmIn = &pDrv->LineIn;
 
-        int rc2 = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pStrmIn->pStrmIn);
-
-        LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
-        if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
+        int rc2 = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, pCfg, &pStrmIn->pStrmIn);
+        LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc2));
+        if (RT_SUCCESS(rc2))
         {
             AudioMixerRemoveStream(pSink, pStrmIn->phStrmIn);
@@ -653,4 +652,7 @@
         }
 
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+
         RTStrFree(pszDesc);
     }
@@ -679,13 +681,16 @@
         }
 
-        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. */
+        int rc2 = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+        LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc2));
+        if (RT_SUCCESS(rc2))
         {
             AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
-            rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
-                                        pDrv->pConnector, pDrv->Out.pStrmOut,
-                                        0 /* uFlags */, &pDrv->Out.phStrmOut);
-        }
+            rc2 = AudioMixerAddStreamOut(pThis->pSinkOutput,
+                                         pDrv->pConnector, pDrv->Out.pStrmOut,
+                                         0 /* uFlags */, &pDrv->Out.phStrmOut);
+        }
+
+        if (RT_SUCCESS(rc))
+            rc = rc2;
 
         RTStrFree(pszDesc);
@@ -712,5 +717,5 @@
     {
         case PI_INDEX:
-            rc = ichac97OpenIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE_IN, pCfg);
+            rc = ichac97OpenIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE, pCfg);
             break;
 
@@ -820,5 +825,5 @@
                 break;
 
-            case PDMAUDIOMIXERCTL_PCM:
+            case PDMAUDIOMIXERCTL_FRONT:
                 rc = AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
                 break;
@@ -875,5 +880,5 @@
         case REC_VIDEO:   return PDMAUDIORECSOURCE_VIDEO;
         case REC_AUX:     return PDMAUDIORECSOURCE_AUX;
-        case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE_IN;
+        case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE;
         case REC_PHONE:   return PDMAUDIORECSOURCE_PHONE;
         default:
@@ -893,5 +898,5 @@
         case PDMAUDIORECSOURCE_VIDEO:   return REC_VIDEO;
         case PDMAUDIORECSOURCE_AUX:     return REC_AUX;
-        case PDMAUDIORECSOURCE_LINE_IN: return REC_LINE_IN;
+        case PDMAUDIORECSOURCE_LINE: return REC_LINE_IN;
         case PDMAUDIORECSOURCE_PHONE:   return REC_PHONE;
         default:
@@ -969,5 +974,5 @@
 
     ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME,  0x8000);
-    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM,     0x8808);
+    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,   0x8808);
     ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
 
@@ -1806,5 +1811,5 @@
                     break;
                 case AC97_PCM_Out_Volume_Mute:
-                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_PCM, u32Val);
+                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_FRONT, u32Val);
                     break;
                 case AC97_Line_In_Volume_Mute:
@@ -2045,5 +2050,5 @@
 # define V_(a, b) ichac97MixerSetVolume(pThis, a, b, ichac97MixerGet(pThis, a))
     V_(AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME);
-    V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM);
+    V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
     V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
 # undef V_
Index: /trunk/src/VBox/Devices/Audio/DevIchHda.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 60353)
@@ -33,4 +33,5 @@
 #include <iprt/asm.h>
 #include <iprt/asm-math.h>
+#include <iprt/file.h>
 #include <iprt/list.h>
 #ifdef IN_RING3
@@ -46,4 +47,5 @@
 #include "AudioMixer.h"
 #include "DevIchHdaCodec.h"
+#include "DevIchHdaCommon.h"
 #include "DrvAudio.h"
 
@@ -85,15 +87,38 @@
 #define BIRD_THINKS_CORBRP_IS_MOSTLY_RO
 
-#define HDA_NREGS           114
-#define HDA_NREGS_SAVED     112
+/* Make sure that interleaving streams support is enabled if the 5.1 code
+ * is being used. */
+#ifdef VBOX_WITH_HDA_51_SURROUND
+# define VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
+#endif
 
 /**
- *  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()).
+ * At the moment we support 4 input + 4 output streams (for 7.1 support) max,
+ * which is 12 in total. Bidirectional streams are currently *not* supported.
  *
- *  The au32Regs[] layout is kept unchanged for saved state
- *  compatibility. */
+ * 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
+
+/**
+ * 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.
+ */
 
 /* Registers */
@@ -114,12 +139,12 @@
  * iss (11:8)  - number of input streams supported
  * bss (7:3)   - number of bidirectional streams supported
- * bds (2:1)   - number of serial data out signals supported
+ * bds (2:1)   - number of serial data out (SDO) 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)  << 2)    \
+    (  (((oss)   & 0xF) << 12) \
+     | (((iss)   & 0xF) << 8)  \
+     | (((bss)   & 0xF) << 3)  \
+     | (((bds)   & 0x3) << 1)  \
      | ((b64sup) & 1))
 
@@ -187,5 +212,5 @@
 #define HDA_INTSTS_S_MASK(num)      RT_BIT(HDA_REG_FIELD_SHIFT(S##num))
 
-#define HDA_REG_WALCLK              13 /* 0x24 */
+#define HDA_REG_WALCLK              13 /* 0x30 */
 #define HDA_RMX_WALCLK              /* Not defined! */
 
@@ -194,5 +219,5 @@
  * the datasheet.
  */
-#define HDA_REG_SSYNC               14 /* 0x34 */
+#define HDA_REG_SSYNC               14 /* 0x38 */
 #define HDA_RMX_SSYNC               12
 
@@ -290,12 +315,14 @@
 #define HDA_SD_NUM_FROM_REG(pThis, func, reg)   ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
 
-#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 */
+/** @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_RMX_SD0CTL              32
 #define HDA_RMX_SD1CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
@@ -471,15 +498,8 @@
 #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_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 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 HDA_REG_SD0BDPL             42 /* 0x98 */
@@ -585,4 +605,6 @@
     /** Unused, padding. */
     bool                fPadding;
+    /** Mutex semaphore handle to serialize access. */
+    RTSEMMUTEX          hMtx;
     /** Event signalling that the stream's state has been changed. */
     RTSEMEVENT          hStateChangedEvent;
@@ -599,14 +621,14 @@
 typedef struct HDASTREAM
 {
-    /** Stream number (SDn). */
-    uint8_t        u8Strm;
-    uint8_t        Padding0[7];
+    /** Stream descriptor number (SDn). */
+    uint8_t                 u8SD;
+    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
@@ -614,26 +636,41 @@
      *
      *  Must be a power of two. */
-    uint16_t       u16FIFOS;
+    uint16_t                u16FIFOS;
     /** Last Valid Index (SDnLVI). */
-    uint16_t       u16LVI;
-    uint16_t       Padding1[3];
+    uint16_t                u16LVI;
+    uint16_t                Padding1[3];
+    /** Pointer to mixer sink this stream is attached to. */
+    R3PTRTYPE(PAUDMIXSINK)  pSink;
     /** Internal state of this stream. */
-    HDASTREAMSTATE State;
+    HDASTREAMSTATE          State;
 } HDASTREAM, *PHDASTREAM;
 
+/**
+ * Structure for mapping a stream tag to
+ * an internal stream state.
+ */
+typedef struct HDATAG
+{
+    /** Own Tag. */
+    uint8_t               uTag;
+    uint8_t               Padding[7];
+    /** Pointer to associated stream. */
+    R3PTRTYPE(PHDASTREAM) pStrm;
+} HDATAG, *PHDATAG;
+
 typedef struct HDAINPUTSTREAM
 {
-    /** PCM line input stream. */
-    R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
-    /** Mixer handle for line input stream. */
-    R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
+    /** Pointer to guest input stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMIN) pGstStrm;
+    /** Associated mixer handle. */
+    R3PTRTYPE(PAUDMIXSTREAM)      pMixStrm;
 } HDAINPUTSTREAM, *PHDAINPUTSTREAM;
 
 typedef struct HDAOUTPUTSTREAM
 {
-    /** PCM output stream. */
-    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
-    /** Mixer handle for line output stream. */
-    R3PTRTYPE(PAUDMIXSTREAM)           phStrmOut;
+    /** Pointer to guest output stream. */
+    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pGstStrm;
+    /** Associated mixer handle. */
+    R3PTRTYPE(PAUDMIXSTREAM)       pMixStrm;
 } HDAOUTPUTSTREAM, *PHDAOUTPUTSTREAM;
 
@@ -666,8 +703,16 @@
     /** Stream for line input. */
     HDAINPUTSTREAM                     LineIn;
+#ifdef VBOX_WITH_HDA_MIC_IN
     /** Stream for mic input. */
     HDAINPUTSTREAM                     MicIn;
-    /** Stream for output. */
-    HDAOUTPUTSTREAM                    Out;
+#endif
+    /** Stream for front output. */
+    HDAOUTPUTSTREAM                    Front;
+#ifdef VBOX_WITH_HDA_51_SURROUND
+    /** Stream for center/LFE output. */
+    HDAOUTPUTSTREAM                    CenterLFE;
+    /** Stream for rear output. */
+    HDAOUTPUTSTREAM                    Rear;
+#endif
 } HDADRIVER;
 
@@ -691,11 +736,9 @@
     RTGCPHYS                           MMIOBaseAddr;
     /** The HDA's register set. */
-    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;
+    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];
     /** CORB buffer base address. */
     uint64_t                           u64CORBBase;
@@ -719,5 +762,5 @@
     /** Size in bytes of RIRB buffer. */
     uint32_t                           cbRirbBuf;
-    /** Indicates if HDA is in reset. */
+    /** Indicates if HDA controller is in reset mode. */
     bool                               fInReset;
     /** Flag whether the R0 part is enabled. */
@@ -748,9 +791,15 @@
     R3PTRTYPE(PAUDIOMIXER)             pMixer;
     /** Audio sink for PCM output. */
-    R3PTRTYPE(PAUDMIXSINK)             pSinkOutput;
+    R3PTRTYPE(PAUDMIXSINK)             pSinkFront;
+#ifdef VBOX_WITH_HDA_51_SURROUND
+    R3PTRTYPE(PAUDMIXSINK)             pSinkCenterLFE;
+    R3PTRTYPE(PAUDMIXSINK)             pSinkRear;
+#endif
     /** Audio mixer sink for line input. */
     R3PTRTYPE(PAUDMIXSINK)             pSinkLineIn;
+#ifdef VBOX_WITH_HDA_MIC_IN
     /** Audio mixer sink for microphone input. */
     R3PTRTYPE(PAUDMIXSINK)             pSinkMicIn;
+#endif
     uint64_t                           u64BaseTS;
     /** Response Interrupt Count (RINTCNT). */
@@ -758,4 +807,9 @@
     /** Padding for alignment. */
     uint8_t                            au8Padding2[7];
+#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
+    /** Circular buffer for interleaving streams support.
+     *  This is needed for extracting multiple channels out of a single HDA stream. */
+    R3PTRTYPE(PRTCIRCBUF)              pCircBuf;
+#endif
 } HDASTATE;
 /** Pointer to the ICH Intel HD Audio Controller state. */
@@ -785,16 +839,22 @@
  * Global register set read/write functions.
  */
-static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 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 hdaRegWriteINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegReadSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
+static int hdaRegWriteSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 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 pu32Value);
+static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegReadOUTPAY(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
+static int hdaRegWriteOUTPAY(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegReadOUTSTRMPAY(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
+static int hdaRegWriteOUTSTRMPAY(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
@@ -804,14 +864,15 @@
  * {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);
-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);
-inline bool hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+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(int)  hdaRegWriteSDLock(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t iReg, uint32_t u32Value);
+DECLINLINE(void) hdaRegWriteSDUnlock(PHDASTREAM pStrmSt);
 
 /*
@@ -819,11 +880,11 @@
  */
 static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
+static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 
 #ifdef IN_RING3
@@ -832,5 +893,5 @@
 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);
+static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbToProcess, uint32_t *pcbProcessed);
 #endif
 
@@ -911,5 +972,5 @@
     /** Descripton. */
     const char *desc;
-} g_aHdaRegMap[HDA_NREGS] =
+} g_aHdaRegMap[HDA_NUM_REGS] =
 
 {
@@ -919,5 +980,5 @@
     { 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          , hdaRegWriteUnimpl     , HDA_REG_IDX(OUTPAY)       }, /* Output Payload Capabilities */
+    { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadOUTPAY       , hdaRegWriteOUTPAY     , 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 */
@@ -925,10 +986,10 @@
     { 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          , hdaRegWriteUnimpl     , HDA_REG_IDX(OUTSTRMPAY)   }, /* Output Stream Payload Capability */
+    { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadOUTSTRMPAY   , hdaRegWriteOUTSTRMPAY , 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 */
     { 0x00030, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadWALCLK       , hdaRegWriteUnimpl     , HDA_REG_IDX_LOCAL(WALCLK) }, /* Wall Clock Counter */
-    { 0x00034, 0x00004, 0x000000FF, 0x000000FF, hdaRegReadU32          , hdaRegWriteU32        , HDA_REG_IDX(SSYNC)        }, /* Stream Synchronization */
+    { 0x00034, 0x00004, 0x000000FF, 0x000000FF, hdaRegReadSSYNC        , hdaRegWriteSSYNC      , HDA_REG_IDX(SSYNC)        }, /* Stream Synchronization */
     { 0x00040, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32          , hdaRegWriteBase       , HDA_REG_IDX(CORBLBASE)    }, /* CORB Lower Base Address */
     { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32          , hdaRegWriteBase       , HDA_REG_IDX(CORBUBASE)    }, /* CORB Upper Base Address */
@@ -1033,8 +1094,8 @@
 
     LogFlowFunc(("[SD%RU8]: LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
-                 pStrmSt->u8Strm, u32LPIB, pThis->fDMAPosition));
+                 pStrmSt->u8SD, u32LPIB, pThis->fDMAPosition));
 
     /* Update LPIB in any case. */
-    HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) = u32LPIB;
+    HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD) = u32LPIB;
 
     /* Do we need to tell the current DMA position? */
@@ -1042,10 +1103,7 @@
     {
         int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
-                                        (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStrmSt->u8Strm * 2 * sizeof(uint32_t)),
+                                        (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStrmSt->u8SD * 2 * sizeof(uint32_t)),
                                         (void *)&u32LPIB, sizeof(uint32_t));
         AssertRC(rc2);
-#ifdef DEBUG
-        hdaBDLEDumpAll(pThis, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
-#endif
     }
 }
@@ -1141,44 +1199,16 @@
 
 #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));
+    LogFlowFunc(("[SD%RU8]: uOldBDLE=%RU16, uCurBDLE=%RU16, LVI=%RU32, rc=%Rrc, %R[bdle]\n",
+                 pStrmSt->u8SD, uOldBDLE, pStrmSt->State.uCurBDLE, pStrmSt->u16LVI, rc, &pStrmSt->State.BDLE));
 #endif
     return rc;
 }
-#endif
-
-DECLINLINE(PHDASTREAM) hdaStreamFromID(PHDASTATE pThis, uint8_t uStreamID)
-{
-    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;
-        }
-
-        default:
-        {
-            pStrmSt = NULL;
-            LogFunc(("Warning: Stream with ID=%RU8 not handled\n", uStreamID));
-            break;
-        }
-    }
-
-    return pStrmSt;
+#endif /* IN_RING3 */
+
+DECLINLINE(PHDASTREAM) hdaStreamFromSD(PHDASTATE pThis, uint8_t uSD)
+{
+    AssertPtrReturn(pThis, NULL);
+    AssertReturn(uSD <= HDA_MAX_STREAMS, NULL);
+    return &pThis->aStreams[uSD];
 }
 
@@ -1197,5 +1227,5 @@
 
 #ifdef VBOX_HDA_WITH_FIFO
-    return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStrmSt->u8Strm));
+    return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStrmSt->u8SD));
 #else
     return 0;
@@ -1210,4 +1240,6 @@
 
     bool fIrq = false;
+
+    /** @todo Optimize IRQ handling. */
 
     if (/* Controller Interrupt Enable (CIE). */
@@ -1218,11 +1250,13 @@
         fIrq = true;
 
-    /** @todo Don't hardcode stream numbers here. */
     if (   IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 0)
-        || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4))
-    {
-#ifdef IN_RING3
-        LogFunc(("BCIS\n"));
-#endif
+        || 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))
+    {
         fIrq = true;
     }
@@ -1230,5 +1264,5 @@
     if (HDA_REG_FLAG_VALUE(pThis, INTCTL, GIE))
     {
-        LogFunc(("%s\n", fIrq ? "Asserted" : "Deasserted"));
+        Log3Func(("%s\n", fIrq ? "Asserted" : "Deasserted"));
         PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , fIrq);
     }
@@ -1472,18 +1506,24 @@
 }
 
-static int hdaStreamCreate(PHDASTREAM pStrmSt)
+static int hdaStreamCreate(PHDASTREAM pStrmSt, uint8_t uSD)
 {
     AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+    AssertReturn(uSD <= HDA_MAX_STREAMS, VERR_INVALID_PARAMETER);
 
     int rc = RTSemEventCreate(&pStrmSt->State.hStateChangedEvent);
-    AssertRC(rc);
-
-    pStrmSt->u8Strm         = UINT8_MAX;
-
-    pStrmSt->State.fActive  = false;
-    pStrmSt->State.fInReset = false;
-    pStrmSt->State.fDoStop  = false;
-
-    LogFlowFuncLeaveRC(rc);
+    if (RT_SUCCESS(rc))
+        rc = RTSemMutexCreate(&pStrmSt->State.hMtx);
+
+    if (RT_SUCCESS(rc))
+    {
+        pStrmSt->u8SD           = uSD;
+        pStrmSt->pSink          = NULL;
+
+        pStrmSt->State.fActive  = false;
+        pStrmSt->State.fInReset = false;
+        pStrmSt->State.fDoStop  = false;
+    }
+
+    LogFlowFunc(("uSD=%RU8\n", uSD));
     return rc;
 }
@@ -1493,13 +1533,21 @@
     AssertPtrReturnVoid(pStrmSt);
 
-    LogFlowFunc(("[SD%RU8]: Destroy\n", pStrmSt->u8Strm));
+    LogFlowFunc(("[SD%RU8]: Destroy\n", pStrmSt->u8SD));
 
     int rc2 = hdaStreamStop(pStrmSt);
     AssertRC(rc2);
 
+    if (pStrmSt->State.hMtx != NIL_RTSEMMUTEX)
+    {
+        rc2 = RTSemMutexDestroy(pStrmSt->State.hMtx);
+        AssertRC(rc2);
+        pStrmSt->State.hMtx = NIL_RTSEMMUTEX;
+    }
+
     if (pStrmSt->State.hStateChangedEvent != NIL_RTSEMEVENT)
     {
         rc2 = RTSemEventDestroy(pStrmSt->State.hStateChangedEvent);
         AssertRC(rc2);
+        pStrmSt->State.hStateChangedEvent = NIL_RTSEMEVENT;
     }
 
@@ -1507,15 +1555,15 @@
 }
 
-static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
+static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8SD)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-    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));
+    pStrmSt->u8SD       = u8SD;
+    pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrmSt->u8SD),
+                                      HDA_STREAM_REG(pThis, BDPU, pStrmSt->u8SD));
+    pStrmSt->u16LVI     = HDA_STREAM_REG(pThis, LVI, pStrmSt->u8SD);
+    pStrmSt->u32CBL     = HDA_STREAM_REG(pThis, CBL, pStrmSt->u8SD);
+    pStrmSt->u16FIFOS   = hdaSDFIFOSToBytes(HDA_STREAM_REG(pThis, FIFOS, pStrmSt->u8SD));
 
     RT_ZERO(pStrmSt->State.BDLE);
@@ -1523,11 +1571,11 @@
 
     LogFlowFunc(("[SD%RU8]: DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16\n",
-                 pStrmSt->u8Strm, pStrmSt->u64BDLBase, pStrmSt->u32CBL, pStrmSt->u16LVI, pStrmSt->u16FIFOS));
+                 pStrmSt->u8SD, pStrmSt->u64BDLBase, pStrmSt->u32CBL, pStrmSt->u16LVI, pStrmSt->u16FIFOS));
 
 #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);
+    uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrmSt->u8SD),
+                                      HDA_STREAM_REG(pThis, BDPU, pStrmSt->u8SD));
+    uint16_t u16LVI     = HDA_STREAM_REG(pThis, LVI, pStrmSt->u8SD);
+    uint32_t u32CBL     = HDA_STREAM_REG(pThis, CBL, pStrmSt->u8SD);
 
     LogFlowFunc(("\t-> DMA @ 0x%x, LVI=%RU16, CBL=%RU32\n", u64BaseDMA, u16LVI, u32CBL));
@@ -1543,9 +1591,9 @@
     AssertPtrReturnVoid(pThis);
     AssertPtrReturnVoid(pStrmSt);
-    AssertReturnVoid(u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
+    AssertReturnVoid(u8Strm <= HDA_MAX_STREAMS);
 
 #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));
+                     ("[SD%RU8] Cannot reset stream while in running state\n", u8Strm));
 #endif
 
@@ -1559,5 +1607,6 @@
      * First, reset the internal stream state.
      */
-    RT_BZERO(pStrmSt, sizeof(HDASTREAM));
+    RT_ZERO(pStrmSt->State.BDLE);
+    pStrmSt->State.uCurBDLE = 0;
 
     /*
@@ -1575,21 +1624,24 @@
     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, FMT,   u8Strm) = 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,  u8Strm) = 0;
     HDA_STREAM_REG(pThis, BDPL,  u8Strm) = 0;
 
     /*
-     * Third, set the internal state according to the just set registers.
+     * Third, match the internal state to the just set registers.
      */
-    pStrmSt->u8Strm   = u8Strm;
-    pStrmSt->u16FIFOS = HDA_STREAM_REG(pThis, FIFOS, u8Strm);
-
-
-    /* Report that we're done resetting this stream. */
-    HDA_STREAM_REG(pThis, CTL,   u8Strm) = 0;
+    pStrmSt->u8SD       = u8Strm;
+    pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
+                                      HDA_STREAM_REG(pThis, BDPU, u8Strm));
+    pStrmSt->u32CBL     = HDA_STREAM_REG(pThis, CBL,   u8Strm);
+    pStrmSt->u16FIFOS   = HDA_STREAM_REG(pThis, FIFOS, u8Strm);
+    pStrmSt->u16FMT     = HDA_STREAM_REG(pThis, FMT,   u8Strm);
+    pStrmSt->u16LVI     = HDA_STREAM_REG(pThis, LVI,   u8Strm);
 
     LogFunc(("[SD%RU8]: Reset\n", u8Strm));
 
-    /* Exit reset mode. */
+    /* Exit reset state. */
     ASMAtomicXchgBool(&pStrmSt->State.fInReset, false);
 }
@@ -1644,5 +1696,5 @@
     AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
 
-    LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStrmSt->u8Strm, msTimeout));
+    LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStrmSt->u8SD, msTimeout));
     return RTSemEventWait(pStrmSt->State.hStateChangedEvent, msTimeout);
 }
@@ -1728,5 +1780,5 @@
         if (pThis->fInReset)
         {
-            LogFunc(("Leaving reset\n"));
+            LogFunc(("Guest leaving HDA reset\n"));
             pThis->fInReset = false;
         }
@@ -1736,17 +1788,12 @@
 #ifdef IN_RING3
         /* Enter reset state. */
-        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 mode. */
+        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"));
+
+        /* Clear the CRST bit to indicate that we're in reset state. */
         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
@@ -1754,4 +1801,5 @@
 #endif
     }
+
     if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, FSH))
     {
@@ -1771,4 +1819,36 @@
     pThis->au32Regs[iRegMem] &= ~(v & nv); /* write of 1 clears corresponding bit */
     return VINF_SUCCESS;
+}
+
+static int hdaRegReadOUTPAY(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
+{
+    uint16_t u16OUTSTRMPAY = HDA_REG(pThis, OUTPAY);
+    LogFlowFunc(("%RU16\n", u16OUTSTRMPAY));
+
+    if (pu32Value)
+        *pu32Value = u16OUTSTRMPAY;
+    return VINF_SUCCESS;
+}
+
+static int hdaRegWriteOUTPAY(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+{
+    LogFlowFunc(("%RU16\n", (uint16_t)u32Value));
+    return hdaRegWriteU16(pThis, iReg, u32Value);
+}
+
+static int hdaRegReadOUTSTRMPAY(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
+{
+    uint16_t u16OUTSTRMPAY = HDA_REG(pThis, OUTSTRMPAY);
+    LogFlowFunc(("%RU16\n", u16OUTSTRMPAY));
+
+    if (pu32Value)
+        *pu32Value = u16OUTSTRMPAY;
+    return VINF_SUCCESS;
+}
+
+static int hdaRegWriteOUTSTRMPAY(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+{
+    LogFlowFunc(("%RU16\n", (uint16_t)u32Value));
+    return hdaRegWriteU16(pThis, iReg, u32Value);
 }
 
@@ -1784,27 +1864,18 @@
     }
 
-#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(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
+    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+    {
+        const uint32_t u32STS = HDA_STREAM_REG(pThis, STS, i);
+        bool fReport =    (u32STS & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE))
+                       || (u32STS & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE))
+                       || (u32STS & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS));
+        v |= fReport ? RT_BIT(i) : 0;
+    }
 
     v |= v ? RT_BIT(31) : 0;
 
-    *pu32Value = v;
+    if (pu32Value)
+        *pu32Value = v;
+
     return VINF_SUCCESS;
 }
@@ -1829,4 +1900,18 @@
     LogFlowFunc(("%RU32\n", *pu32Value));
     return VINF_SUCCESS;
+}
+
+static int hdaRegReadSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
+{
+    /* 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);
 }
 
@@ -1880,32 +1965,41 @@
     rc = hdaCORBCmdProcess(pThis);
     return rc;
-#else
+#else  /* !IN_RING3 */
     return VINF_IOM_R3_MMIO_WRITE;
-#endif
+#endif /* IN_RING3 */
 }
 
 static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    int rc = hdaRegWriteU32(pThis, iReg, u32Value);
-    if (RT_SUCCESS(rc))
-    {
-        uint8_t u8Strm  = HDA_SD_NUM_FROM_REG(pThis, CBL, iReg);
-
-        PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
-        if (pStrmSt)
-        {
-            pStrmSt->u32CBL = u32Value;
-
-            /* Reset BDLE state. */
-            RT_ZERO(pStrmSt->State.BDLE);
-            pStrmSt->State.uCurBDLE = 0;
-        }
-
-        LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
-    }
-    else
-        AssertRCReturn(rc, VINF_SUCCESS);
-
-    return rc;
+#ifdef IN_RING3
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+        return VINF_SUCCESS;
+
+    PHDASTREAM pStrmSt = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, CBL, iReg));
+    if (!pStrmSt)
+    {
+        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);
+    }
+
+    int rc2 = hdaRegWriteSDLock(pThis, pStrmSt, iReg, u32Value);
+    AssertRC(rc2);
+
+    pStrmSt->u32CBL = u32Value;
+
+    /* Reset BDLE state. */
+    RT_ZERO(pStrmSt->State.BDLE);
+    pStrmSt->State.uCurBDLE = 0;
+
+    rc2 = hdaRegWriteU32(pThis, iReg, u32Value);
+    AssertRC(rc2);
+
+    LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", pStrmSt->u8SD, u32Value));
+    hdaRegWriteSDUnlock(pStrmSt);
+
+    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+#else  /* !IN_RING3 */
+    return VINF_IOM_R3_MMIO_WRITE;
+#endif /* IN_RING3 */
 }
 
@@ -1917,21 +2011,60 @@
     bool fInReset  = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
 
-    uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
-
-    PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
-    if (!pStrmSt)
-    {
-        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. */
-    }
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+        return VINF_SUCCESS;
+
+    /* Get the stream descriptor. */
+    uint8_t uSD = 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;
+
+    /* Tag 0 is reserved for software / invalid, just skip. */
+    if (   !uTag
+        || (uTag > HDA_MAX_TAGS))
+    {
+        LogFunc(("[SD%RU8]: Warning: Invalid stream tag %RU8 specified!\n", uSD, uTag));
+        return hdaRegWriteU24(pThis, iReg, u32Value);
+    }
+
+#ifdef IN_RING3
+    PHDATAG pTag = &pThis->aTags[uTag];
+    AssertPtr(pTag);
+
+    if (pTag->uTag)
+        LogFunc(("[SD%RU8]: Warning: Tag %RU8 already assigned to %RU8 (pStrm=%p)\n", uSD, uTag, pTag->uTag, pTag->pStrm));
+
+    /* Assign new values. */
+    pTag->uTag  = uTag;
+    pTag->pStrm = hdaStreamFromSD(pThis, uSD);
+
+    LogFunc(("[SD%RU8]: Using stream tag=%RU8\n", uSD, uTag));
+
+    PHDASTREAM pStrmSt = pTag->pStrm;
+    AssertPtr(pStrmSt);
+
+    /* Note: Do not use hdaRegWriteSDLock() here, as SDnCTL might change the RUN bit. */
+    int rc2 = RTSemMutexRequest(pStrmSt->State.hMtx, RT_INDEFINITE_WAIT);
+    AssertRC(rc2);
+#endif /* IN_RING3 */
 
     LogFunc(("[SD%RU8]: fRun=%RTbool, fInRun=%RTbool, fReset=%RTbool, fInReset=%RTbool, %R[sdctl]\n",
-             u8Strm, fRun, fInRun, fReset, fInReset, u32Value));
+             uSD, fRun, fInRun, fReset, fInReset, u32Value));
 
     if (fInReset)
     {
-        /* Guest is resetting HDA's stream, we're expecting guest will mark stream as exit. */
         Assert(!fReset);
-        LogFunc(("Guest initiated exit of stream reset\n"));
+        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));
     }
     else if (fReset)
@@ -1941,8 +2074,6 @@
         Assert(!fInRun && !fRun);
 
-        LogFunc(("Guest initiated enter to stream reset\n"));
-        hdaStreamReset(pThis, pStrmSt, u8Strm);
-#else
-        return VINF_IOM_R3_MMIO_WRITE;
+        LogFunc(("[SD%RU8]: Guest initiated enter to stream reset\n", pStrmSt->u8SD));
+        hdaStreamReset(pThis, pStrmSt, pStrmSt->u8SD);
 #endif
     }
@@ -1956,54 +2087,62 @@
         {
             Assert(!fReset && !fInReset);
-            LogFunc(("[SD%RU8]: fRun=%RTbool\n", u8Strm, fRun));
-
+            LogFunc(("[SD%RU8]: fRun=%RTbool\n", pStrmSt->u8SD, fRun));
+
+            Assert(pStrmSt->u8SD < HDA_MAX_STREAMS);
+
+            /*
+             * 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.
+             */
             PHDADRIVER pDrv;
-            switch (u8Strm)
+            if (pStrmSt->u8SD < HDA_MAX_SDI)
             {
-                case 0: /** @todo Use a variable here. Later. */
+# ifdef VBOX_WITH_HDA_MIC_IN
+#  error "Implement mic-in support!"
+# else
+                RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+                        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+                                                      pDrv->LineIn.pGstStrm, fRun);
+# endif
+            }
+            else
+            {
+                RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
                 {
-                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
-                        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
-                                                      pDrv->LineIn.pStrmIn, fRun);
-                    break;
+                    pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Front.pGstStrm,     fRun);
+# ifdef VBOX_WITH_HDA_51_SURROUND
+                    pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->CenterLFE.pGstStrm, fRun);
+                    pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Rear.pGstStrm,      fRun);
+# endif
                 }
-# 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, pStrmSt, u8Strm);
-
-#else /* !IN_RING3 */
-        return VINF_IOM_R3_MMIO_WRITE;
+            hdaStreamInit(pThis, pStrmSt, pStrmSt->u8SD);
 #endif /* IN_RING3 */
     }
 
-    return hdaRegWriteU24(pThis, iReg, u32Value);
+#ifdef IN_RING3
+    rc2 = hdaRegWriteU24(pThis, iReg, u32Value);
+    AssertRC(rc2);
+
+    hdaRegWriteSDUnlock(pStrmSt);
+    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+#else
+    return VINF_IOM_R3_MMIO_WRITE;
+#endif
 }
 
 static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    uint32_t v = HDA_REG_IND(pThis, iReg);
-    v &= ~(u32Value & v);
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+        return VINF_SUCCESS;
+
+    uint32_t v  = HDA_REG_IND(pThis, iReg);
+             v &= ~(u32Value & v);
     HDA_REG_IND(pThis, iReg) = v;
+
     hdaProcessInterrupt(pThis);
     return VINF_SUCCESS;
@@ -2012,32 +2151,42 @@
 static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
+#ifdef IN_RING3
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
         return VINF_SUCCESS;
 
-    int rc = hdaRegWriteU16(pThis, iReg, u32Value);
-    if (RT_SUCCESS(rc))
-    {
-        uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
-
-        PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
-        if (pStrmSt)
-        {
-            pStrmSt->u16LVI = u32Value;
-
-            /* Reset BDLE state. */
-            RT_ZERO(pStrmSt->State.BDLE);
-            pStrmSt->State.uCurBDLE = 0;
-        }
-
-        LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
-    }
-    else
-        AssertRCReturn(rc, VINF_SUCCESS);
-
-    return rc;
+    PHDASTREAM pStrmSt = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, LVI, iReg));
+    if (!pStrmSt)
+    {
+        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, pStrmSt, iReg, u32Value);
+    AssertRC(rc2);
+
+    /** @todo Validate LVI. */
+    pStrmSt->u16LVI = u32Value;
+
+    /* Reset BDLE state. */
+    RT_ZERO(pStrmSt->State.BDLE);
+    pStrmSt->State.uCurBDLE = 0;
+
+    rc2 = hdaRegWriteU16(pThis, iReg, u32Value);
+    AssertRC(rc2);
+
+    LogFlowFunc(("[SD%RU8]: LVI=%RU32\n", pStrmSt->u8SD, u32Value));
+    hdaRegWriteSDUnlock(pStrmSt);
+
+    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+#else  /* !IN_RING3 */
+    return VINF_IOM_R3_MMIO_WRITE;
+#endif /* IN_RING3 */
 }
 
 static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+        return VINF_SUCCESS;
+
     switch (u32Value)
     {
@@ -2059,53 +2208,33 @@
 static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+        return VINF_SUCCESS;
+
     /** @todo Only allow updating FIFOS if RUN bit is 0? */
     uint32_t u32FIFOS = 0;
 
-    switch (iReg)
-    {
-        /* 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"));
+    /** @todo Check if this is a SDI and deny writes to this. */
+    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_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_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;
-        }
-        default:
-        {
-            AssertMsgFailed(("Something weird happened with register lookup routine\n"));
-            break;
-        }
     }
 
     if (u32FIFOS)
     {
-        LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n", 0, hdaSDFIFOSToBytes(u32FIFOS)));
+        LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n",
+                 HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg), hdaSDFIFOSToBytes(u32FIFOS)));
         /** @todo Update internal stream state with new FIFOS. */
 
@@ -2158,27 +2287,27 @@
     }
 
-    PDMAUDIOFMT enmFmt = AUD_FMT_S16; /* Default to 16-bit signed. */
+    PDMAUDIOFMT enmFmt      = AUD_FMT_S16; /* Default to 16-bit signed. */
+    uint8_t     cSampleBits = 16;
     switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))
     {
         case 0:
-            LogFunc(("Requested 8-bit\n"));
-            enmFmt = AUD_FMT_S8;
+            enmFmt      = AUD_FMT_S8;
+            cSampleBits = 8;
             break;
         case 1:
-            LogFunc(("Requested 16-bit\n"));
-            enmFmt = AUD_FMT_S16;
+            enmFmt      = AUD_FMT_S16;
             break;
         case 2:
-            LogFunc(("Requested 20-bit\n"));
+            cSampleBits = 20;
             break;
         case 3:
-            LogFunc(("Requested 24-bit\n"));
+            cSampleBits = 24;
             break;
         case 4:
-            LogFunc(("Requested 32-bit\n"));
-            enmFmt = AUD_FMT_S32;
+            enmFmt      = AUD_FMT_S32;
+            cSampleBits = 32;
             break;
         default:
-            AssertMsgFailed(("Unsupported bits shift %x\n",
+            AssertMsgFailed(("Unsupported bits per sample %x\n",
                              EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)));
             rc = VERR_NOT_SUPPORTED;
@@ -2195,6 +2324,4 @@
 
 # undef EXTRACT_VALUE
-
-    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -2204,9 +2331,4 @@
 {
 #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;
-
     PDMAUDIOSTREAMCFG strmCfg;
     int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);
@@ -2214,33 +2336,61 @@
         return VINF_SUCCESS; /* Always return success to the MMIO handler. */
 
-    uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, FMT, iReg);
-
-    PHDADRIVER pDrv;
-    switch (iReg)
-    {
-        case HDA_REG_SD0FMT:
-            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
-                rc = hdaCodecOpenStream(pThis->pCodec, PI_INDEX, &strmCfg);
-            break;
-#  ifdef VBOX_WITH_HDA_MIC_IN
-        case HDA_REG_SD2FMT:
-            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
-                rc = hdaCodecOpenStream(pThis->pCodec, MC_INDEX, &strmCfg);
-            break;
-#  endif
-        case HDA_REG_SD4FMT:
-            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
-                rc = hdaCodecOpenStream(pThis->pCodec, PO_INDEX, &strmCfg);
-            break;
-        default:
-            LogFunc(("Warning: Changing SDFMT on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
-            break;
-    }
-
-    /** @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
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+        return VINF_SUCCESS;
+
+    PHDASTREAM pStrmSt = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, FMT, iReg));
+    if (!pStrmSt)
+    {
+        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);
+    }
+
+    rc = hdaRegWriteSDLock(pThis, pStrmSt, iReg, u32Value);
+    AssertRC(rc);
+
+    LogFlowFunc(("[SD%RU8]: Hz=%RU32, Channels=%RU8, enmFmt=%RU32\n",
+                 pStrmSt->u8SD, strmCfg.uHz, strmCfg.cChannels, strmCfg.enmFormat));
+
+    PDMAUDIOMIXERCTL enmMixerCtl;
+#ifdef VBOX_WITH_HDA_51_SURROUND
+# error "Implement me!"
+#endif
+
+    enmMixerCtl = PDMAUDIOMIXERCTL_FRONT;
+    strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+
+    if (RT_SUCCESS(rc))
+    {
+        PHDADRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+        {
+            int rc2 = hdaCodecRemoveStream(pThis->pCodec, enmMixerCtl);
+            if (RT_SUCCESS(rc2))
+                rc2 = hdaCodecAddStream(pThis->pCodec, enmMixerCtl, &strmCfg);
+
+            if (   RT_FAILURE(rc2)
+                && (pDrv->Flags & PDMAUDIODRVFLAG_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", pStrmSt->u8SD, rc));
+
+        hdaRegWriteSDUnlock(pStrmSt);
+    }
+
+    return VINF_SUCCESS; /* Never return failure. */
 #else /* !IN_RING3 */
     return VINF_IOM_R3_MMIO_WRITE;
@@ -2251,24 +2401,35 @@
 DECLINLINE(int) hdaRegWriteSDBDPX(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t u8Strm)
 {
-    if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
+#ifdef IN_RING3
+    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
         return VINF_SUCCESS;
 
-    int rc = hdaRegWriteU32(pThis, iReg, u32Value);
-    if (RT_SUCCESS(rc))
-    {
-        PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
-        if (pStrmSt)
-        {
-            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);
-
-    return rc;
+    PHDASTREAM pStrmSt = hdaStreamFromSD(pThis, u8Strm);
+    if (!pStrmSt)
+    {
+        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, pStrmSt, iReg, u32Value);
+    AssertRC(rc2);
+
+    rc2 = hdaRegWriteU32(pThis, iReg, u32Value);
+    AssertRC(rc2);
+
+    /* Update BDL base. */
+    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;
+
+    LogFlowFunc(("[SD%RU8]: BDLBase=0x%x\n", pStrmSt->u8SD, pStrmSt->u64BDLBase));
+    hdaRegWriteSDUnlock(pStrmSt);
+
+    return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+#else  /* !IN_RING3 */
+    return VINF_IOM_R3_MMIO_WRITE;
+#endif /* IN_RING3 */
 }
 
@@ -2283,6 +2444,7 @@
 }
 
+#ifdef IN_RING3
 /**
- * Checks whether a write to a specific SDnXXX register is allowed or not.
+ * XXX
  *
  * @return  bool                Returns @true if write is allowed, @false if not.
@@ -2291,30 +2453,43 @@
  * @param   u32Value            Value to write.
  */
-inline bool hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
+DECLINLINE(int) hdaRegWriteSDLock(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t iReg, uint32_t u32Value)
+{
+    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+
+#ifdef VBOX_STRICT
     /* Check if the SD's RUN bit is set. */
-    bool fIsRunning = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+    uint32_t u32SDCTL = HDA_STREAM_REG(pThis, CTL, pStrmSt->u8SD);
+    bool fIsRunning   = RT_BOOL(u32SDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
     if (fIsRunning)
     {
-#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;
-    }
-
-    return true;
-}
+        LogFlowFunc(("[SD%RU8]: Warning: Cannot write to register 0x%x (0x%x) when RUN bit is set (%R[sdctl])\n",
+                     pStrmSt->u8SD, iReg, u32Value, u32SDCTL));
+        return VERR_ACCESS_DENIED;
+    }
+#endif
+
+    return RTSemMutexRequest(pStrmSt->State.hMtx, RT_INDEFINITE_WAIT);
+}
+
+DECLINLINE(void) hdaRegWriteSDUnlock(PHDASTREAM pStrmSt)
+{
+    AssertPtrReturnVoid(pStrmSt);
+
+    int rc2 = RTSemMutexRelease(pStrmSt->State.hMtx);
+    AssertRC(rc2);
+}
+#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 */
-
-    rc = hdaRegReadU32(pThis, iReg, pu32Value);
-    return rc;
+    }
+
+    return hdaRegReadU32(pThis, iReg, pu32Value);
 }
 
@@ -2364,4 +2539,5 @@
         return rc;
     }
+
     /*
      * Once the guest read the response, it should clean the IRV bit of the IRS register.
@@ -2376,8 +2552,7 @@
 {
     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;
 }
@@ -2532,5 +2707,5 @@
     PHDABDLE pBDLE = &pStrmSt->State.BDLE;
 
-    uint32_t cbFree = pStrmSt->u32CBL - HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
+    uint32_t cbFree = pStrmSt->u32CBL - HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD);
     if (cbFree)
     {
@@ -2557,6 +2732,6 @@
     }
 
-    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));
+    LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, cbFree=%RU32, %R[bdle]\n", pStrmSt->u8SD,
+                 pStrmSt->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD), cbFree, pBDLE));
     return cbFree;
 }
@@ -2602,5 +2777,5 @@
 
     PHDABDLE pBDLE   = &pStrmSt->State.BDLE;
-    uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
+    uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD);
 
     /* Did we reach the CBL (Cyclic Buffer List) limit? */
@@ -2616,5 +2791,5 @@
 
     LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32, fCBLLimitReached=%RTbool, fNeedsNextBDLE=%RTbool, %R[bdle]\n",
-                 pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
+                 pStrmSt->u8SD, u32LPIB, pStrmSt->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
 
     if (fCBLLimitReached)
@@ -2633,5 +2808,5 @@
     AssertPtrReturnVoid(pStrmSt);
 
-    LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStrmSt->u8Strm, cbInc));
+    LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStrmSt->u8SD, cbInc));
 
     Assert(cbInc <= pStrmSt->u16FIFOS);
@@ -2646,10 +2821,10 @@
     if (pBDLE->State.cbBelowFIFOW == 0) /* Did we hit (or exceed) the watermark? */
     {
-        const uint32_t u32LPIB = RT_MIN(HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
+        const uint32_t u32LPIB = RT_MIN(HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD) + cbInc,
                                         pStrmSt->u32CBL);
 
         LogFlowFunc(("[SD%RU8]: LPIB: %RU32 -> %RU32, CBL=%RU32\n",
-                     pStrmSt->u8Strm,
-                     HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
+                     pStrmSt->u8SD,
+                     HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD), HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD) + cbInc,
                      pStrmSt->u32CBL));
 
@@ -2666,5 +2841,5 @@
 
     PHDABDLE       pBDLE   = &pStrmSt->State.BDLE;
-    const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
+    const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8SD);
 
     if (   pBDLE->State.u32BufOff >= pBDLE->u32BufSize
@@ -2690,5 +2865,5 @@
              * but in general sound quality gets worse.
              */
-            HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
+            HDA_STREAM_REG(pThis, STS, pStrmSt->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
 
             /*
@@ -2696,5 +2871,5 @@
              * we need to generate an interrupt.
              */
-            if (HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
+            if (HDA_STREAM_REG(pThis, CTL, pStrmSt->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
                 hdaProcessInterrupt(pThis);
         }
@@ -2704,5 +2879,5 @@
 
     LogFlowFunc(("[SD%RU8]: u32LPIB=%RU32, CBL=%RU32, %R[bdle] => %s\n",
-                 pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE"));
+                 pStrmSt->u8SD, u32LPIB, pStrmSt->u32CBL, pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE"));
 
     return fIsComplete;
@@ -2714,9 +2889,8 @@
  *       but "reports bytes" when all conditions are met (FIFOW).
  */
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, PAUDMIXSINK pSink, uint32_t cbMax, uint32_t *pcbRead)
+static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax, uint32_t *pcbRead)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-    AssertPtrReturn(pSink,   VERR_INVALID_POINTER);
     /* pcbRead is optional. */
 
@@ -2736,5 +2910,5 @@
     else
     {
-        rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
+        rc = AudioMixerProcessSinkIn(pStrmSt->pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
         if (RT_SUCCESS(rc))
         {
@@ -2814,4 +2988,12 @@
         AssertRC(rc);
 
+#if 0
+        RTFILE fh;
+        RTFileOpen(&fh, "c:\\temp\\hdaWriteAudio.pcm",
+                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        RTFileWrite(fh, pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW, cbData, NULL);
+        RTFileClose(fh);
+#endif
+
 #ifdef VBOX_WITH_STATISTICS
         STAM_COUNTER_ADD(&pThis->StatBytesRead, cbData);
@@ -2829,8 +3011,114 @@
             RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
             {
-                if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+                if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Front.pGstStrm))
                 {
+#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
+                    /** @todo Needs more hacking first. */
+# if 0
+                    static int16_t restBuf = 0;
+                    static size_t cbRestOff = 0;
+
+                    uint8_t temp[HDA_SDONFIFO_256B + 1];
+
+                    uint8_t *pu8Src = &pBDLE->State.au8FIFO[0];
+                    uint8_t *pu8Dst = &temp[0];
+
+                    size_t cbSample = sizeof(int16_t) * 2;
+
+                    size_t cbProc     = 0;
+                    size_t cbToSkip   = 5 * cbSample;
+                    size_t cbSkipSize = cbToSkip;
+                    size_t cbDstSize  = 0;
+
+                    while (cbProc < cbToWrite)
+                    {
+                        memcpy(pu8Dst, pu8Src, cbSample);
+
+                        cbSkipSize = RT_MIN(cbToSkip, cbToWrite - cbProc);
+
+                        pu8Src += 10;
+                        cbProc += cbSkipSize;
+
+                        pu8Dst    += 4;
+                        cbDstSize += cbSample;
+                    }
+
+                    /* Sanity. */
+                    AssertMsg(((cbDstSize * 8 /* Bit */) % 16) == 0, ("ASDF\n"));
+
+                    LogFlowFunc(("cbRest=%zu, cbToWrite=%zu, cbProc=%zu, cbDstSize=%zu\n",
+                                 0, cbToWrite, cbProc, cbDstSize));
+
                     rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+                                                     temp, cbDstSize, &cbWrittenToStream);
+# if 1
+                    RTFILE fh;
+                    RTFileOpen(&fh, "/tmp/hdaWriteAudio.pcm",
+                               RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+                    RTFileWrite(fh, temp, cbDstSize, NULL);
+                    RTFileClose(fh);
+# endif
+
+# else
+                    int16_t *pvStart;
+                    size_t cbAcqWrite;
+                    RTCircBufAcquireWriteBlock(pThis->pCircBuf, cbToWrite, (void **)&pvStart, &cbAcqWrite);
+
+                    uint8_t cChannels = 1;
+                    size_t cbSample = sizeof(int16_t);
+
+                    int16_t *pi16Src = (int16_t *)&pBDLE->State.au8FIFO[0];
+                    int16_t *pi16Dst = pvStart;
+
+                    size_t cbProcSrc     = 0;
+                    size_t cbProcDst     = 0;
+
+                    while (cbProcSrc < cbAcqWrite)
+                    {
+                        memcpy(pi16Dst, pi16Src, cbSample);
+
+                        pi16Src  += 6 * cChannels;
+                        pi16Dst  += cChannels;
+
+                        cbProcSrc += RT_MIN(cbAcqWrite - cbProcSrc, 6 * cbSample);
+                        cbProcDst += cbSample;
+
+                        Assert(cbProcSrc <= cbAcqWrite);
+                        size_t cbLeft = cbAcqWrite - cbProcSrc;
+                        LogFlowFunc(("cbProcSrc=%zu, cbProcDst=%zu, cbLeft=%zu\n", cbProcSrc, cbProcDst, cbLeft));
+                        if (   cbLeft
+                            && cbLeft < cChannels)
+                        {
+                            LogFlowFunc(("%zu bytes left ...\n", cbAcqWrite - cbProcSrc));
+                            break;
+                        }
+                    }
+
+                    RTCircBufReleaseWriteBlock(pThis->pCircBuf, cbProcDst);
+
+                    LogFlowFunc(("cbAcqWrite=%zu, cbToWrite=%zu, cbProcSrc=%zu, cbProcDst=%zu\n",
+                                 cbAcqWrite, cbToWrite, cbProcSrc, cbProcDst));
+
+                    size_t cbAcqRead = 0;
+                    RTCircBufAcquireReadBlock(pThis->pCircBuf, _4K, (void **)&pvStart, &cbAcqRead);
+# if 1
+                    RTFILE fh;
+                    RTFileOpen(&fh, "/tmp/hdaWriteAudio.pcm",
+                               RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+                    RTFileWrite(fh, pvStart, cbAcqRead, NULL);
+                    RTFileClose(fh);
+# endif
+                    rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Front.pGstStrm,
+                                                     pvStart, cbAcqRead, &cbWrittenToStream);
+
+                    /** @todo Add support for writing to center/LFE + rear. */
+
+                    RTCircBufReleaseReadBlock(pThis->pCircBuf, cbAcqRead);
+# endif
+
+#else  /* !VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT */
+                    rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Front.pGstStrm,
                                                      pBDLE->State.au8FIFO, cbToWrite, &cbWrittenToStream);
+#endif /* VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT */
                     if (RT_SUCCESS(rc2))
                     {
@@ -2891,46 +3179,65 @@
 }
 
-
-static DECLCALLBACK(void) hdaCloseIn(PHDASTATE pThis, PDMAUDIORECSOURCE enmRecSource)
-{
-    NOREF(pThis);
-    NOREF(enmRecSource);
-    LogFlowFuncEnter();
-}
-
-static DECLCALLBACK(void) hdaCloseOut(PHDASTATE pThis)
-{
-    NOREF(pThis);
-    LogFlowFuncEnter();
-}
-
-static DECLCALLBACK(int) hdaOpenIn(PHDASTATE pThis,
-                                   const char *pszName, PDMAUDIORECSOURCE enmRecSource,
-                                   PPDMAUDIOSTREAMCFG pCfg)
+/**
+ * Retrieves a corresponding sink for a given mixer control.
+ * Returns NULL if no sink is found.
+ *
+ * @return  PAUDMIXSINK
+ * @param   pThis               HDA state.
+ * @param   enmMixerCtl         Mixer control to get the corresponding sink for.
+ */
+static PAUDMIXSINK hdaMixerControlToSink(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
 {
     PAUDMIXSINK pSink;
 
-    switch (enmRecSource)
-    {
-# ifdef VBOX_WITH_HDA_MIC_IN
-        case PDMAUDIORECSOURCE_MIC:
+    switch (enmMixerCtl)
+    {
+        case PDMAUDIOMIXERCTL_VOLUME:
+            /* Fall through is intentional. */
+        case PDMAUDIOMIXERCTL_FRONT:
+            pSink = pThis->pSinkFront;
+            break;
+#ifdef VBOX_WITH_HDA_51_SURROUND
+        case PDMAUDIOMIXERCTL_CENTER_LFE:
+            pSink = pThis->pSinkCenterLFE;
+            break;
+        case PDMAUDIOMIXERCTL_REAR:
+            pSink = pThis->pSinkRear;
+            break;
+#endif
+        case PDMAUDIOMIXERCTL_LINE_IN:
+            pSink = pThis->pSinkLineIn;
+            break;
+#ifdef VBOX_WITH_HDA_MIC_IN
+        case PDMAUDIOMIXERCTL_MIC_IN:
             pSink = pThis->pSinkMicIn;
             break;
-# endif
-        case PDMAUDIORECSOURCE_LINE_IN:
-            pSink = pThis->pSinkLineIn;
+#endif
+        default:
+            pSink = NULL;
+            AssertMsgFailed(("Unhandled mixer control\n"));
             break;
-        default:
-            AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
-            return VERR_NOT_SUPPORTED;
-    }
+    }
+
+    return pSink;
+}
+
+static DECLCALLBACK(int) hdaMixerAddStreamIn(PHDASTATE pThis, PAUDMIXSINK pSink, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
+
+    AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER);
+
+    LogFunc(("Sink=%s, Source=%ld\n", pSink->pszName, pCfg->DestSource.Source));
 
     int rc = VINF_SUCCESS;
-    char *pszDesc;
 
     PHDADRIVER pDrv;
     RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     {
-        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
+        char *pszDesc;
+        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pCfg->pszName) <= 0)
         {
             rc = VERR_NO_MEMORY;
@@ -2938,13 +3245,40 @@
         }
 
-        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. */
+        int rc2 = VINF_SUCCESS;
+        PHDAINPUTSTREAM pStream;
+        switch (pCfg->DestSource.Source)
         {
-            AudioMixerRemoveStream(pSink, pDrv->LineIn.phStrmIn);
-            rc = AudioMixerAddStreamIn(pSink,
-                                       pDrv->pConnector, pDrv->LineIn.pStrmIn,
-                                       0 /* uFlags */, &pDrv->LineIn.phStrmIn);
+            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;
         }
+
+        if (RT_SUCCESS(rc2))
+        {
+            PPDMAUDIOGSTSTRMIN pGstStrm;
+            PAUDMIXSTREAM      pMixStrm;
+
+            rc2 = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, pCfg, &pGstStrm);
+            LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+            if (RT_SUCCESS(rc2))
+                rc2 = AudioMixerAddStreamIn(pSink, pDrv->pConnector, pGstStrm, 0 /* uFlags */, &pMixStrm);
+
+            if (RT_SUCCESS(rc2))
+            {
+                pStream->pGstStrm = pGstStrm;
+                pStream->pMixStrm = pMixStrm;
+            }
+        }
+
+        if (RT_SUCCESS(rc))
+            rc = rc2;
 
         RTStrFree(pszDesc);
@@ -2955,15 +3289,22 @@
 }
 
-static DECLCALLBACK(int) hdaOpenOut(PHDASTATE pThis,
-                                    const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
-{
+static DECLCALLBACK(int) hdaMixerAddStreamOut(PHDASTATE pThis, PAUDMIXSINK pSink, PPDMAUDIOSTREAMCFG pCfg)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
+
+    AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
+
+    LogFunc(("Sink=%s, Dest=%ld\n", pSink->pszName, pCfg->DestSource.Dest));
+
     int rc = VINF_SUCCESS;
-    char *pszDesc;
 
     PHDADRIVER pDrv;
     RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     {
+        char *pszDesc;
         if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
-                         pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
+                         pDrv->uLUN, pCfg->pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
         {
             rc = VERR_NO_MEMORY;
@@ -2971,13 +3312,43 @@
         }
 
-        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. */
+        int rc2 = VINF_SUCCESS;
+        PHDAOUTPUTSTREAM pStream;
+        switch (pCfg->DestSource.Dest)
         {
-            AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
-            rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
-                                        pDrv->pConnector, pDrv->Out.pStrmOut,
-                                        0 /* uFlags */, &pDrv->Out.phStrmOut);
+            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;
         }
+
+        if (RT_SUCCESS(rc2))
+        {
+            PPDMAUDIOGSTSTRMOUT pGstStrm;
+            PAUDMIXSTREAM       pMixStrm;
+
+            rc2 = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pGstStrm);
+            LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc2));
+            if (RT_SUCCESS(rc2))
+                rc2 = AudioMixerAddStreamOut(pSink, pDrv->pConnector, pGstStrm, 0 /* uFlags */, &pMixStrm);
+
+            if (RT_SUCCESS(rc2))
+            {
+                pStream->pGstStrm = pGstStrm;
+                pStream->pMixStrm = pMixStrm;
+            }
+        }
+
+        if (RT_SUCCESS(rc))
+            rc = rc2;
 
         RTStrFree(pszDesc);
@@ -2988,30 +3359,104 @@
 }
 
-static DECLCALLBACK(int) hdaSetVolume(PHDASTATE pThis, ENMSOUNDSOURCE enmSource,
-                                      bool fMute, uint8_t uVolLeft, uint8_t uVolRight)
-{
-    int             rc = VINF_SUCCESS;
-    PDMAUDIOVOLUME  vol = { fMute, uVolLeft, uVolRight };
-    PAUDMIXSINK     pSink;
-
-    /* Convert the audio source to corresponding sink. */
-    switch (enmSource)
-    {
-        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;
-    }
-
-    /* Set the volume. Codec already converted it to the correct range. */
-    AudioMixerSetSinkVolume(pSink, &vol);
+/**
+ * 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;
+
+    PAUDMIXSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
+    if (pSink)
+    {
+        if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
+        {
+            rc = hdaMixerAddStreamIn(pThis, pSink, pCfg);
+        }
+        else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
+        {
+            rc = hdaMixerAddStreamOut(pThis, pSink, pCfg);
+        }
+        else
+        {
+            rc = VERR_INVALID_PARAMETER;
+            AssertFailed();
+        }
+    }
+    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)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    int rc;
+
+    PAUDMIXSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
+    if (pSink)
+    {
+        if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
+        {
+            /** @todo Remove streams. */
+        }
+        else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
+        {
+            /** @todo Remove streams. */
+        }
+        else
+        {
+            rc = VERR_INVALID_PARAMETER;
+            AssertFailed();
+        }
+    }
+    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)
+{
+    int rc;
+
+    PAUDMIXSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
+    if (pSink)
+    {
+        /* Set the volume.
+         * We assume that the codec already converted it to the correct range. */
+        rc = AudioMixerSetSinkVolume(pSink, pVol);
+    }
+    else
+        rc = VERR_NOT_FOUND;
 
     LogFlowFuncLeaveRC(rc);
@@ -3032,4 +3477,5 @@
     uint32_t cbOutMin = UINT32_MAX;
 
+    int rc;
     PHDADRIVER pDrv;
 
@@ -3044,11 +3490,12 @@
      */
     AssertPtr(pThis->pCodec);
-    PDMPCMPROPS codecStrmProps;
-
-    int rc = DrvAudioStreamCfgToProps(&pThis->pCodec->strmCfg, &codecStrmProps);
-    AssertRC(rc);
-
-    uint32_t cCodecSamplesMin  = (int)((2 * cTicksElapsed * pThis->pCodec->strmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
-    uint32_t cbCodecSamplesMin = cCodecSamplesMin << codecStrmProps.cShift;
+
+    /* Since the codec always runs at a fixed delivery rate (48 kHz), calculate the sample processing rate based
+     * on the clock ticks elapsed (the clock itself runs at 24 Mhz).
+     * A stream itself can have a higher or lower delivery rate, which in turn then results in more or less
+     * stream samples per frame. */
+    uint32_t cCodecSamplesMin  = (int)((2 * cTicksElapsed * 48000 /* Hz */ + cTicksPerSec) / cTicksPerSec / 2);
+    /* We always use 32-bit as containers to make sure all data is being pumped if we need to. */
+    uint32_t cbCodecSamplesMin = cCodecSamplesMin << 1;
 
     /*
@@ -3073,5 +3520,5 @@
          * 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))
+        if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Front.pGstStrm))
         {
             /* Use the codec's (fixed) sampling rate. */
@@ -3080,10 +3527,10 @@
         }
 
-        const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+        const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Front.pGstStrm);
         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);
+            uint32_t cSamplesMin  = (int)((2 * cTicksElapsed * pDrv->Front.pGstStrm->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+            uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Front.pGstStrm->MixBuf, cSamplesMin);
 
 #ifdef DEBUG_TIMER
@@ -3104,7 +3551,11 @@
         cbOutMin = 0;
 
+    /** @todo Determine the streams to be handled. */
+    PHDASTREAM pStrmStIn  = &pThis->aStreams[0];
+    PHDASTREAM pStrmStOut = &pThis->aStreams[4];
+
     /* Do the actual device transfers. */
-    hdaTransfer(pThis, PO_INDEX, cbOutMin /* cbToProcess */, NULL /* pcbProcessed */);
-    hdaTransfer(pThis, PI_INDEX, cbInMax  /* cbToProcess */, NULL /* pcbProcessed */);
+    hdaTransfer(pThis, pStrmStOut, cbOutMin /* cbToProcess */, NULL /* pcbProcessed */);
+    hdaTransfer(pThis, pStrmStIn,  cbInMax  /* cbToProcess */, NULL /* pcbProcessed */);
 
     /* Kick the timer again. */
@@ -3166,7 +3617,8 @@
 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
 
-static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbToProcess, uint32_t *pcbProcessed)
+{
+    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
     /* pcbProcessed is optional. */
 
@@ -3180,38 +3632,11 @@
     }
 
-    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;
-        }
-
-        default:
-        {
-            AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
-            return VERR_NOT_SUPPORTED;
-        }
-    }
-
-    int  rc       = VINF_SUCCESS;
     bool fProceed = true;
+    int rc = RTSemMutexRequest(pStrmSt->State.hMtx, RT_INDEFINITE_WAIT);
+    if (RT_FAILURE(rc))
+        return rc;
 
     /* Stop request received? */
-    if (ASMAtomicReadBool(&pStrmSt->State.fDoStop))
+    if (pStrmSt->State.fDoStop)
     {
         pStrmSt->State.fActive = false;
@@ -3223,5 +3648,5 @@
     }
     /* Is the stream not in a running state currently? */
-    else if (!(HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
+    else if (!(HDA_STREAM_REG(pThis, CTL, pStrmSt->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
         fProceed = false;
     /* Nothing to process? */
@@ -3231,4 +3656,7 @@
     if (!fProceed)
     {
+        rc = RTSemMutexRelease(pStrmSt->State.hMtx);
+        AssertRC(rc);
+
         if (pcbProcessed)
             *pcbProcessed = 0;
@@ -3236,13 +3664,11 @@
     }
 
-    LogFlowFunc(("enmSrc=%RU32, cbToProcess=%RU32\n", enmSrc, cbToProcess));
-
     /* Sanity checks. */
-    Assert(pStrmSt->u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
+    Assert(pStrmSt->u8SD <= HDA_MAX_STREAMS);
     Assert(pStrmSt->u64BDLBase);
     Assert(pStrmSt->u32CBL);
 
     /* State sanity checks. */
-    Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false);
+    Assert(pStrmSt->State.fInReset == false);
 
     uint32_t cbProcessedTotal = 0;
@@ -3253,31 +3679,26 @@
         /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
         if (hdaStreamNeedsNextBDLE(pThis, pStrmSt))
-            hdaStreamGetNextBDLE(pThis, pStrmSt);
-
-        /* 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);
-
-        uint32_t cbProcessed;
-        switch (enmSrc)
         {
-            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;
+            rc = hdaStreamGetNextBDLE(pThis, pStrmSt);
+            if (RT_FAILURE(rc))
                 break;
         }
 
+        /* Set the FIFORDY bit on the stream while doing the transfer. */
+        HDA_STREAM_REG(pThis, STS, pStrmSt->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+
+        /*
+         * 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.
+         */
+        uint32_t cbProcessed;
+        if (pStrmSt->u8SD < HDA_MAX_SDI)
+            rc = hdaReadAudio (pThis, pStrmSt, cbToProcess, &cbProcessed);
+        else
+            rc = hdaWriteAudio(pThis, pStrmSt, cbToProcess, &cbProcessed);
+
         /* Remove the FIFORDY bit again. */
-        HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+        HDA_STREAM_REG(pThis, STS, pStrmSt->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
 
         if (RT_FAILURE(rc))
@@ -3307,6 +3728,11 @@
             *pcbProcessed = cbProcessedTotal;
     }
-
-    LogFlowFuncLeaveRC(rc);
+    else
+        LogFlowFunc(("Failed with %Rrc\n", rc));
+
+    int rc2 = RTSemMutexRelease(pStrmSt->State.hMtx);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
     return rc;
 }
@@ -3337,12 +3763,12 @@
 #endif
 
-    LogFunc(("offReg=%#x cb=%#x\n", offReg, cb));
+    Log3Func(("offReg=%#x cb=%#x\n", offReg, cb));
     Assert(cb == 4); Assert((offReg & 3) == 0);
 
     if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
-        LogFunc(("\tAccess to registers except GCTL is blocked while reset\n"));
+        LogFunc(("Access to registers except GCTL is blocked while reset\n"));
 
     if (idxRegDsc == -1)
-        LogRel(("HDA: Invalid read access @0x%x (bytes=%d)\n", offReg, cb));
+        LogRel(("HDA: Invalid read access @0x%x (bytes=%u)\n", offReg, cb));
 
     if (idxRegDsc != -1)
@@ -3355,5 +3781,5 @@
              */
             rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, (uint32_t *)pv);
-            LogFunc(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
+            Log3Func(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
         }
         else
@@ -3371,5 +3797,5 @@
 
                 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, &u32Tmp);
-                LogFunc(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
+                Log3Func(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
                 if (rc != VINF_SUCCESS)
                     break;
@@ -3390,5 +3816,5 @@
     {
         rc = VINF_IOM_MMIO_UNUSED_FF;
-        LogFunc(("\tHole at %x is accessed for read\n", offReg));
+        Log3Func(("\tHole at %x is accessed for read\n", offReg));
     }
 
@@ -3398,9 +3824,9 @@
 #ifdef LOG_ENABLED
     if (cbLog == 4)
-        LogFunc(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
+        Log3Func(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
     else if (cbLog == 2)
-        LogFunc(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
+        Log3Func(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
     else if (cbLog == 1)
-        LogFunc(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
+        Log3Func(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
 #endif
     return rc;
@@ -3421,6 +3847,6 @@
 #endif
     int rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pThis, idxRegDsc, u32Value);
-    LogFunc(("write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
-             g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
+    Log3Func(("write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
+              g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
     return rc;
 }
@@ -3464,14 +3890,14 @@
     uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
     if (idxRegDsc == -1)
-        LogFunc(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
+        Log3Func(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
     else if (cb == 4)
-        LogFunc(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+        Log3Func(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
     else if (cb == 2)
-        LogFunc(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+        Log3Func(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
     else if (cb == 1)
-        LogFunc(("@%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+        Log3Func(("@%#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)
-        LogFunc(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
+        Log3Func(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
 #endif
 
@@ -3482,7 +3908,5 @@
     {
         rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "");
-#ifdef LOG_ENABLED
-        LogFunc(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
-#endif
+        Log3Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
     }
     /*
@@ -3504,6 +3928,6 @@
             u64Value <<= cbBefore * 8;
             u64Value  |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
-            LogFunc(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
-                     cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
+            Log3Func(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
+                      cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
         }
 
@@ -3520,10 +3944,10 @@
                 {
                     u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
-                    LogFunc(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
-                             g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
+                    Log3Func(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
+                              g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
                 }
                 uint32_t u32LogOldVal = pThis->au32Regs[idxRegMem];
                 rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "*");
-                LogFunc(("\t%#x -> %#x\n", u32LogOldVal, pThis->au32Regs[idxRegMem]));
+                Log3Func(("\t%#x -> %#x\n", u32LogOldVal, pThis->au32Regs[idxRegMem]));
             }
             else
@@ -3615,10 +4039,10 @@
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
-    LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
+    LogFlowFunc(("[SD%RU8]\n", pStrm->u8SD));
 
     /* Save stream ID. */
-    int rc = SSMR3PutU8(pSSM, pStrm->u8Strm);
+    int rc = SSMR3PutU8(pSSM, pStrm->u8SD);
     AssertRCReturn(rc, rc);
-    Assert(pStrm->u8Strm <= 7); /** @todo Use a define. */
+    Assert(pStrm->u8SD <= HDA_MAX_STREAMS);
 
     rc = SSMR3PutStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE), 0 /*fFlags*/, g_aSSMStreamStateFields6, NULL);
@@ -3626,8 +4050,8 @@
 
 #ifdef DEBUG /* 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);
+    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);
 
     hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
@@ -3680,24 +4104,17 @@
 
     /* 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. */
-#ifdef VBOX_WITH_HDA_MIC_IN
-    SSMR3PutU32(pSSM, 3);
-#else
-    SSMR3PutU32(pSSM, 2);
-#endif
+    SSMR3PutU32(pSSM, HDA_MAX_STREAMS);
 
     /* Save stream states. */
-    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);
+    int rc;
+    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+    {
+        rc = hdaSaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
+        AssertRCReturn(rc, rc);
+    }
 
     return rc;
@@ -3750,5 +4167,5 @@
         case HDA_SSM_VERSION_3:
             cRegs = 112;
-            AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
+            AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= 112);
             break;
 
@@ -3824,23 +4241,26 @@
 
             /* Output */
-            rc = hdaStreamInit(pThis, &pThis->StrmStOut,    4 /* Stream number, hardcoded */);
+            PHDASTREAM pStream = &pThis->aStreams[4];
+            rc = hdaStreamInit(pThis, pStream, 4 /* Stream descriptor, hardcoded */);
             if (RT_FAILURE(rc))
                 break;
-            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStOut.State.BDLE);
-            pThis->StrmStOut.State.uCurBDLE = pThis->StrmStOut.State.BDLE.State.u32BDLIndex;
+            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
+            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
 
             /* Microphone-In */
-            rc = hdaStreamInit(pThis, &pThis->StrmStMicIn,  2 /* Stream number, hardcoded */);
+            pStream = &pThis->aStreams[2];
+            rc = hdaStreamInit(pThis, pStream, 2 /* Stream descriptor, hardcoded */);
             if (RT_FAILURE(rc))
                 break;
-            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStMicIn.State.BDLE);
-            pThis->StrmStMicIn.State.uCurBDLE = pThis->StrmStMicIn.State.BDLE.State.u32BDLIndex;
+            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
+            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
 
             /* Line-In */
-            rc = hdaStreamInit(pThis, &pThis->StrmStLineIn, 0 /* Stream number, hardcoded */);
+            pStream = &pThis->aStreams[0];
+            rc = hdaStreamInit(pThis, pStream, 0 /* Stream descriptor, hardcoded */);
             if (RT_FAILURE(rc))
                 break;
-            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStLineIn.State.BDLE);
-            pThis->StrmStLineIn.State.uCurBDLE = pThis->StrmStLineIn.State.BDLE.State.u32BDLIndex;
+            HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
+            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
             break;
         }
@@ -3860,25 +4280,24 @@
             for (uint32_t i = 0; i < cStreams; i++)
             {
-                uint8_t uStreamID;
-                rc = SSMR3GetU8(pSSM, &uStreamID);
+                uint8_t uSD;
+                rc = SSMR3GetU8(pSSM, &uSD);
                 if (RT_FAILURE(rc))
                     break;
 
-                PHDASTREAM pStrm = hdaStreamFromID(pThis, uStreamID);
+                PHDASTREAM pStrm = hdaStreamFromSD(pThis, uSD);
                 HDASTREAM  StreamDummy;
 
                 if (!pStrm)
                 {
+                    RT_ZERO(StreamDummy);
                     pStrm = &StreamDummy;
-                    LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uStreamID));
+                    LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uSD));
                     break;
                 }
 
-                RT_BZERO(pStrm, sizeof(HDASTREAM));
-
-                rc = hdaStreamInit(pThis, pStrm, uStreamID);
+                rc = hdaStreamInit(pThis, pStrm, uSD);
                 if (RT_FAILURE(rc))
                 {
-                    LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uStreamID, rc));
+                    LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uSD, rc));
                     break;
                 }
@@ -3972,13 +4391,24 @@
         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
         {
-            rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, fEnableIn);
+            PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
+            rc = pCon->pfnEnableIn(pCon, pDrv->LineIn.pGstStrm, fEnableIn);
             if (RT_FAILURE(rc))
                 break;
 #ifdef VBOX_WITH_HDA_MIC_IN
-            rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, fEnableMicIn);
+            rc = pCon->pfnEnableIn(pCon, pDrv->MicIn.pGstStrm, fEnableMicIn);
             if (RT_FAILURE(rc))
                 break;
 #endif
-            rc = pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, fEnableOut);
+            rc = pCon->pfnEnableOut(pCon, pDrv->Front.pGstStrm,     fEnableOut);
+            if (RT_FAILURE(rc))
+                break;
+#ifdef VBOX_WITH_HDA_51_SURROUND
+            rc = pCon->pfnEnableOut(pCon, pDrv->CenterLFE.pGstStrm, fEnableOut);
+            if (RT_FAILURE(rc))
+                break;
+            rc = pCon->pfnEnableOut(pCon, pDrv->Rear.pGstStrm,      fEnableOut);
+            if (RT_FAILURE(rc))
+                break;
+#endif
             if (RT_FAILURE(rc))
                 break;
@@ -4083,8 +4513,8 @@
 }
 
-static int hdaLookUpRegisterByName(PHDASTATE pThis, const char *pszArgs)
+static int hdaDbgLookupRegByName(PHDASTATE pThis, const char *pszArgs)
 {
     int iReg = 0;
-    for (; iReg < HDA_NREGS; ++iReg)
+    for (; iReg < HDA_NUM_REGS; ++iReg)
         if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs))
             return iReg;
@@ -4097,5 +4527,5 @@
     Assert(   pThis
            && iHdaIndex >= 0
-           && iHdaIndex < HDA_NREGS);
+           && iHdaIndex < HDA_NUM_REGS);
     pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]);
 }
@@ -4104,30 +4534,91 @@
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaDbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-    int iHdaRegisterIndex = hdaLookUpRegisterByName(pThis, pszArgs);
+    int iHdaRegisterIndex = hdaDbgLookupRegByName(pThis, pszArgs);
     if (iHdaRegisterIndex != -1)
         hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
     else
-        for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NREGS; ++iHdaRegisterIndex)
+    {
+        for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NUM_REGS; ++iHdaRegisterIndex)
             hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
-}
-
-static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaStrmIndex)
+    }
+}
+
+static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
 {
     Assert(   pThis
-           && 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 hdaLookUpStreamIndex(PHDASTATE pThis, const char *pszArgs)
-{
-    /* todo: add args parsing */
+           && 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)
+{
+    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);
+
+    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);
+    }
+}
+
+static int hdaDbgLookupStrmIdx(PHDASTATE pThis, const char *pszArgs)
+{
+    /** @todo Add args parsing. */
     return -1;
 }
@@ -4136,12 +4627,12 @@
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaDbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE   pThis         = PDMINS_2_DATA(pDevIns, PHDASTATE);
-    int         iHdaStrmIndex = hdaLookUpStreamIndex(pThis, pszArgs);
+    int         iHdaStrmIndex = hdaDbgLookupStrmIdx(pThis, pszArgs);
     if (iHdaStrmIndex != -1)
         hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
     else
-        for(iHdaStrmIndex = 0; iHdaStrmIndex < 7; ++iHdaStrmIndex)
+        for(iHdaStrmIndex = 0; iHdaStrmIndex < HDA_MAX_STREAMS; ++iHdaStrmIndex)
             hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
 }
@@ -4150,5 +4641,19 @@
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaDbgInfoBDLE(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+    PHDASTATE   pThis         = PDMINS_2_DATA(pDevIns, PHDASTATE);
+    int         iHdaStrmIndex = hdaDbgLookupStrmIdx(pThis, pszArgs);
+    if (iHdaStrmIndex != -1)
+        hdaDbgPrintBDLE(pThis, pHlp, iHdaStrmIndex);
+    else
+        for(iHdaStrmIndex = 0; iHdaStrmIndex < HDA_MAX_STREAMS; ++iHdaStrmIndex)
+            hdaDbgPrintBDLE(pThis, pHlp, iHdaStrmIndex);
+}
+
+/**
+ * @callback_method_impl{FNDBGFHANDLERDEV}
+ */
+static DECLCALLBACK(void) hdaDbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
@@ -4163,5 +4668,5 @@
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaDbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
@@ -4176,5 +4681,5 @@
  * @callback_method_impl{FNDBGFHANDLERDEV}
  */
-static DECLCALLBACK(void) hdaInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaDbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
@@ -4217,15 +4722,5 @@
     PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
 
-    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 */
-    HDA_REG(pThis, OUTPAY)   = 0x003C;                   /* see 6.2.4 */
-    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"));
+    LogFlowFuncEnter();
 
 # ifndef VBOX_WITH_AUDIO_CALLBACKS
@@ -4241,4 +4736,21 @@
 # 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, 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;
+
     /*
      * Stop any audio currently playing and/or recording.
@@ -4247,12 +4759,13 @@
     RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     {
-        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
+        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pGstStrm,      false /* Disable */);
 # ifdef VBOX_WITH_HDA_MIC_IN
-        /* Ignore rc. */
-        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
+        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pGstStrm,       false /* Disable */);
 # endif
-        /* Ditto. */
-        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
-        /* Ditto. */
+        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Front.pGstStrm,     false /* Disable */);
+# ifdef VBOX_WITH_HDA_51_SURROUND
+        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->CenterLFE.pGstStrm, false /* Disable */);
+        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Rear.pGstStrm,      false /* Disable */);
+# endif
     }
 
@@ -4272,24 +4785,13 @@
     pThis->u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns);
 
-    for (uint8_t u8Strm = 0; u8Strm < 8; u8Strm++) /** @todo Use a define here. */
-    {
-        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);
-
-            hdaStreamReset(pThis, pStrmSt, u8Strm);
-        }
-    }
+    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+    {
+        /* 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], i);
+    }
+
+    /* Clear stream tags <-> objects mapping table. */
+    RT_ZERO(pThis->aTags);
 
     /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
@@ -4308,4 +4810,5 @@
 # endif
 
+    LogFlowFuncLeave();
     LogRel(("HDA: Reset\n"));
 }
@@ -4348,7 +4851,6 @@
     pThis->pu64RirbBuf = NULL;
 
-    hdaStreamDestroy(&pThis->StrmStLineIn);
-    hdaStreamDestroy(&pThis->StrmStMicIn);
-    hdaStreamDestroy(&pThis->StrmStOut);
+    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+        hdaStreamDestroy(&pThis->aStreams[i]);
 
     return VINF_SUCCESS;
@@ -4664,4 +5166,9 @@
 
     RTListInit(&pThis->lstDrv);
+#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
+    rc = RTCircBufCreate(&pThis->pCircBuf, _4K);
+    if (RT_FAILURE(rc))
+        return rc;
+#endif
 
     uint8_t uLUN;
@@ -4704,17 +5211,33 @@
             AssertRC(rc);
 
-            /* Add all required audio sinks. */
+            /*
+             * Add mixer output sinks.
+             */
+#ifdef VBOX_WITH_HDA_51_SURROUND
+            rc = AudioMixerAddSink(pThis->pMixer, "[Playback] Front",
+                                   AUDMIXSINKDIR_OUTPUT, &pThis->pSinkFront);
+            AssertRC(rc);
+            rc = AudioMixerAddSink(pThis->pMixer, "[Playback] Center / Subwoofer",
+                                   AUDMIXSINKDIR_OUTPUT, &pThis->pSinkCenterLFE);
+            AssertRC(rc);
+            rc = AudioMixerAddSink(pThis->pMixer, "[Playback] Rear",
+                                   AUDMIXSINKDIR_OUTPUT, &pThis->pSinkRear);
+            AssertRC(rc);
+#else
             rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
-                                   AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
+                                   AUDMIXSINKDIR_OUTPUT, &pThis->pSinkFront);
             AssertRC(rc);
-
+#endif
+            /*
+             * Add mixer input sinks.
+             */
             rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In",
                                    AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
             AssertRC(rc);
-
+#ifdef VBOX_WITH_HDA_MIC_IN
             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 };
@@ -4732,10 +5255,8 @@
 
         /* 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->pfnMixerAddStream    = hdaMixerAddStream;
+        pThis->pCodec->pfnMixerRemoveStream = hdaMixerRemoveStream;
+        pThis->pCodec->pfnMixerSetVolume    = hdaMixerSetVolume;
+        pThis->pCodec->pfnReset             = hdaCodecReset;
 
         pThis->pCodec->pHDAState = pThis; /* Assign HDA controller state to codec. */
@@ -4756,13 +5277,34 @@
     if (RT_SUCCESS(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);
-
+        /*
+         * Create all hardware streams.
+         */
+        for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+        {
+            rc = hdaStreamCreate(&pThis->aStreams[i], i /* uSD */);
+            AssertRC(rc);
+        }
+
+        /*
+         * As we don't have any dynamic stream <-> mixer sink mapping (yet),
+         * hard-wire the associations here.
+         */
+#ifdef VBOX_WITH_HDA_51_SURROUND
+# error "Implement me!" /** @todo */
+#else
+        /* Same goes for the input sink. */
+        for (uint8_t i = 0; i < HDA_MAX_SDI; i++)
+            pThis->aStreams[i].pSink = pThis->pSinkLineIn;
+# ifdef VBOX_WITH_HDA_MIC_IN
+#  error "Implement me!" /** @todo */
+# endif
+        /* Assign all output streams to the one-and-only output sink. */
+        for (uint8_t i = HDA_MAX_SDI; i < HDA_MAX_SDO; i++)
+            pThis->aStreams[i].pSink = pThis->pSinkFront;
+#endif /* VBOX_WITH_HDA_51_SURROUND */
+
+        /*
+         * Initialize the driver chain.
+         */
         PHDADRIVER pDrv;
         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
@@ -4778,9 +5320,9 @@
             AssertPtr(pCon);
 
-            bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
+            bool fValidLineIn = pCon->pfnIsValidIn(pCon,  pDrv->LineIn.pGstStrm);
 #ifdef VBOX_WITH_HDA_MIC_IN
-            bool fValidMicIn  = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
-#endif
-            bool fValidOut    = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
+            bool fValidMicIn  = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pGstStrm);
+#endif
+            bool fValidOut    = pCon->pfnIsValidOut(pCon, pDrv->Front.pGstStrm);
 
             if (    !fValidLineIn
@@ -4885,9 +5427,10 @@
          * Debug and string formatter types.
          */
-        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);
+        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);
 
         rc = RTStrFormatTypeRegister("bdle",    hdaDbgFmtBDLE,    NULL);
Index: /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp	(revision 60353)
@@ -36,4 +36,6 @@
 #include "VBoxDD.h"
 #include "DevIchHdaCodec.h"
+#include "DevIchHdaCommon.h"
+#include "AudioMixer.h"
 
 
@@ -103,7 +105,15 @@
 #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, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID))
-/* Subordinate node count (7.3.4.3)*/
+
+/** 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). */
 #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)
@@ -120,13 +130,17 @@
 #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)
 
-/* 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))
+/* 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))
 /* note: types 0x8-0xe are reserved */
 #define CODEC_F00_09_TYPE_AUDIO_OUTPUT                     (0x0)
@@ -152,5 +166,5 @@
 #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_LSB                               RT_BIT(0)
+#define CODEC_F00_09_CAP_STEREO                            RT_BIT(0)
 
 #define CODEC_F00_09_TYPE(f00_09)                          (((f00_09) >> 20) & 0xF)
@@ -208,5 +222,5 @@
 #define CODEC_F00_0C_CAP_INPUT                             RT_BIT(5)
 #define CODEC_F00_0C_CAP_OUTPUT                            RT_BIT(4)
-#define CODEC_F00_0C_CAP_HP                                RT_BIT(3)
+#define CODEC_F00_0C_CAP_HEADPHONE_AMP                     RT_BIT(3)
 #define CODEC_F00_0C_CAP_PRESENSE_DETECT                   RT_BIT(2)
 #define CODEC_F00_0C_CAP_TRIGGER_REQUIRED                  RT_BIT(1)
@@ -225,10 +239,10 @@
 #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) & 0x1) << 31)                             \
+        (  (((mute_cap)  & 0x1)  << 31)                           \
          | (((step_size) & 0xFF) << 16)                           \
          | (((num_steps) & 0xFF) << 8)                            \
-         | ((offset) & 0xFF))
+         |  ((offset)    & 0xFF))
 
 #define CODEC_F00_0D_CAP_MUTE                              RT_BIT(7)
@@ -239,4 +253,22 @@
 #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                              0x40
+/** 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
@@ -247,5 +279,5 @@
 #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)               \
@@ -272,5 +304,5 @@
 #define CODEC_F00_10_BENING(f00_10)                        ((f00_10) & 0x1)
 
-/* CP/IO Count (7.3.4.14) */
+/* GPIO count (7.3.4.14). */
 #define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \
     (  (((wake) & 0x1) << 31)                                   \
@@ -280,15 +312,15 @@
      | ((numgpio) & 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) & 0x7) << 4)                                    \
-      | ((set) & 0x7))
+/* 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))
 #define CODEC_F05_D3COLD                                   (4)
 #define CODEC_F05_D3                                       (3)
@@ -300,11 +332,18 @@
 #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) & 0x7) >> 4)
-#define CODEC_F05_SET(value)                               (((value) & 0x7))
+#define CODEC_F05_ACT(value)                               (((value) & 0xF0) >> 4)
+#define CODEC_F05_SET(value)                               (((value) & 0xF))
 
 #define CODEC_F05_GE(p0, p1)                               ((p0) <= (p1))
 #define CODEC_F05_LE(p0, p1)                               ((p0) >= (p1))
 
-/* Pin Widged Control (7.3.3.13) */
+/* 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). */
 #define CODEC_F07_VREF_HIZ                                 (0)
 #define CODEC_F07_VREF_50                                  (0x1)
@@ -316,48 +355,24 @@
 #define CODEC_F07_OUT_H_ENABLE                             RT_BIT(7)
 
-/* Unsolicited enabled (7.3.3.14) */
+/* 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). */
 #define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F))
 
-/* 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) */
+/* 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)                       \
@@ -477,8 +492,9 @@
 #define CODEC_F1C_MISC_MASK                                (0xF)
 #define CODEC_F1C_MISC_SHIFT                               (8)
-#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)
+#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)
 
 /* Configuration default: Association */
@@ -486,5 +502,5 @@
 #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
@@ -498,9 +514,9 @@
 #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)            \
@@ -509,14 +525,14 @@
     )
 
-/* 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) << 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)))
+    (  (((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)))
 
 
@@ -585,4 +601,5 @@
 {
     CODECCOMMONNODE node;
+    uint32_t    u32F01_param;
     uint32_t    u32F03_param;
     uint32_t    u32F05_param;
@@ -591,5 +608,4 @@
 
     uint32_t    u32A_param;
-    uint32_t    u32F01_param;
     AMPLIFIER   B_params;
 } ADCNODE, *PADCNODE;
@@ -627,6 +643,6 @@
     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);
@@ -635,8 +651,8 @@
 {
     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;
@@ -648,10 +664,11 @@
     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, 5);
+AssertNodeSize(DIGOUTNODE, 6);
 
 typedef struct DIGINNODE
@@ -723,6 +740,8 @@
     uint32_t    u32F07_param;
     uint32_t    u32F1c_param;
+
+    uint32_t    u32A_param;
 } RESNODE, *PRESNODE;
-AssertNodeSize(RESNODE, 4);
+AssertNodeSize(RESNODE, 5);
 
 /**
@@ -773,11 +792,15 @@
 #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 */
@@ -788,34 +811,22 @@
 #define STAC9220_NID_AMP_ADC0                              0x17 /* In */
 #define STAC9220_NID_AMP_ADC1                              0x18 /* In */
-/* STAC9221. */
+/* Only for STAC9221. */
 #define STAC9221_NID_ADAT_OUT                              0x19 /* Out */
 #define STAC9221_NID_I2S_OUT                               0x1A /* Out */
 #define STAC9221_NID_PIN_I2S_OUT                           0x1B /* Out */
 
-#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};
+/** 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 };
 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 };
@@ -824,5 +835,4 @@
 /** @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. */
@@ -854,5 +864,5 @@
 static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
-    for (int i = 1; i < 12; i++)
+    for (int i = 1; i < pThis->cTotalNodes; i++)
     {
         PCODECNODE pNode = &pThis->paNodes[i];
@@ -867,103 +877,192 @@
 
 
-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 0:
-            pNode->node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */
+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.id = uNID;
+
+    switch (uNID)
+    {
+        /* 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);
             break;
-        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  */
+        }
+
+        /*
+         * 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_PRESENSE_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,
+                                                                0 /* Step size */,
+                                                                CODEC_AMP_NUM_STEPS,
+                                                                0 /* Initial offset */);
+            /* 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. */
             pNode->afg.u32F08_param = 0;
             pNode->afg.u32F17_param = 0;
             break;
-        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);
+        }
+
+        /*
+         * 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);
             AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
-
-            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;
+        }
+
+        /*
+         * ADCs.
+         */
+        case STAC9220_NID_ADC0: /* Analog input. */
+        {
+            pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC0;
             goto adc_init;
-        case 7:
-            pNode->node.au32F02_param[0] = 0x18;
+        }
+
+        case STAC9220_NID_ADC1: /* Analog input (CD). */
+        {
+            pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC1;
+
+            /* Fall through is intentional. */
         adc_init:
-            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.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.u32F03_param = RT_BIT(0);
-            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);
+            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, 13, 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 */);
             break;
-        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;
+        }
+
+        /*
+         * 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);
             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 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;
+        }
+
+        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];
             pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
-            pNode->spdifin.u32F06_param = 0;
-            pNode->spdifin.u32F0d_param = 0;
+
+            /* 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;
             break;
-        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;
+        }
+
+        /*
+         * PINs / Ports.
+         */
+        case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
+        {
+            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_PRESENSE_DETECT
+                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
+
+            /* Connection list entry 0: Goes to DAC0. */
+            pNode->port.node.au32F02_param[0]   = STAC9220_NID_DAC0;
+
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
@@ -972,36 +1071,44 @@
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_GREEN,
-                                                          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;
+                                                          CODEC_F1C_MISC_NONE,
+                                                          CODEC_F1C_ASSOCIATION_GROUP_0, 0xF /* Seq */);
             goto port_init;
-        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;
+        }
+
+        case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
+        {
+            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_PRESENSE_DETECT
+                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
+
+            /* Connection list entry 0: Goes to DAC2. */
+            pNode->port.node.au32F02_param[0]   = STAC9220_NID_DAC2;
+
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
-                                                          CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR,
+                                                          CODEC_F1C_LOCATION_REAR,
                                                           CODEC_F1C_DEVICE_SPEAKER,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_BLACK,
-                                                          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;
+                                                          CODEC_F1C_MISC_NONE,
+                                                          CODEC_F1C_ASSOCIATION_GROUP_1, 0xE /* Seq */);
             goto port_init;
-        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;
+        }
+
+        case STAC9220_NID_PIN_C: /* Rear Speaker. */
+        {
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, 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_PRESENSE_DETECT
+                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
+
+            /* Connection list entry 0: Goes to DAC1. */
+            pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC1;
+
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
@@ -1010,16 +1117,23 @@
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_GREEN,
-                                                          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;
+                                                          CODEC_F1C_MISC_NONE,
+                                                          CODEC_F1C_ASSOCIATION_GROUP_0, 0x0 /* Seq */);
             goto port_init;
-        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;
+        }
+
+        case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
+        {
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, 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_PRESENSE_DETECT
+                                                | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
+
+            /* Connection list entry 0: Goes to DAC1. */
+            pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC0;
+
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
@@ -1028,47 +1142,64 @@
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_PINK,
-                                                          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;
+                                                          CODEC_F1C_MISC_NONE,
+                                                          CODEC_F1C_ASSOCIATION_GROUP_15, 0xD /* Seq */);
+            /* Fall through is intentional. */
         port_init:
+
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
+                                     | CODEC_F07_OUT_ENABLE;
             pNode->port.u32F08_param = 0;
-            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;
+            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_STEREO;
+            /* Connection list entries. */
+            pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
             break;
-        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);
+        }
+
+        case STAC9220_NID_PIN_E:
+        {
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
             pNode->port.u32F08_param = 0;
-            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;
+            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_UNSOL
+                                                | CODEC_F00_09_CAP_STEREO;
+            pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
+                                                | CODEC_F00_0C_CAP_PRESENSE_DETECT;
+
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
                                                           CODEC_F1C_LOCATION_REAR,
-                                                          CODEC_F1C_DEVICE_LINE_OUT,
+                                                          CODEC_F1C_DEVICE_LINE_IN,
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_BLUE,
-                                                          0x0, 0x4, 0x0);//0x01013040;  /* Line Out */
+                                                          CODEC_F1C_MISC_NONE,
+                                                          CODEC_F1C_ASSOCIATION_GROUP_15, 0xE /* Seq */);
             break;
-        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;
+        }
+
+        case STAC9220_NID_PIN_F:
+        {
+            pNode->port.u32F07_param = CODEC_F07_IN_ENABLE | CODEC_F07_OUT_ENABLE;
             pNode->port.u32F08_param = 0;
-            pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE
-                                     | CODEC_F07_IN_ENABLE;
+            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;
+
             if (!pThis->fInReset)
                 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
@@ -1077,16 +1208,25 @@
                                                           CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
                                                           CODEC_F1C_COLOR_ORANGE,
-                                                          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;
+                                                          CODEC_F1C_MISC_NONE,
+                                                          CODEC_F1C_ASSOCIATION_GROUP_1, 0x0 /* Seq */);
             break;
-        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);
+        }
+
+        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_PRESENSE_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);
             if (!pThis->fInReset)
                 pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
@@ -1095,16 +1235,26 @@
                                                             CODEC_F1C_CONNECTION_TYPE_DIN,
                                                             CODEC_F1C_COLOR_BLACK,
-                                                            0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
+                                                            CODEC_F1C_MISC_NONE,
+                                                            CODEC_F1C_ASSOCIATION_GROUP_2, 0x0 /* Seq */);
             break;
-        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;
+        }
+
+        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;
             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_PRESENSE_DETECT;
             if (!pThis->fInReset)
                 pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
@@ -1113,36 +1263,65 @@
                                                            CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
                                                            CODEC_F1C_COLOR_BLACK,
-                                                           0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60;
+                                                           CODEC_F1C_MISC_NONE,
+                                                           CODEC_F1C_ASSOCIATION_GROUP_3, 0x0 /* Seq */);
             break;
-        case 0x12:
-            pNode->adcmux.u32F01_param = 0;
+        }
+
+        case STAC9220_NID_ADC0_MUX:
+        {
+            pNode->adcmux.u32F01_param = 0; /* Connection select control index (STAC9220_NID_PIN_E). */
             goto adcmux_init;
-        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);
+        }
+
+        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_BZERO(pNode->adcmux.B_params, AMPLIFIER_SIZE);
             break;
-        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;
+        }
+
+        case STAC9220_NID_PCBEEP:
+        {
             pNode->pcbeep.u32F0a_param = 0;
-            memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
+
+            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_BZERO(pNode->pcbeep.B_params, AMPLIFIER_SIZE);
             break;
-        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);
+        }
+
+        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;
+
             if (!pThis->fInReset)
                 pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
@@ -1151,60 +1330,104 @@
                                                             CODEC_F1C_CONNECTION_TYPE_ATAPI,
                                                             CODEC_F1C_COLOR_UNKNOWN,
-                                                            0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90);
+                                                            CODEC_F1C_MISC_NONE,
+                                                            CODEC_F1C_ASSOCIATION_GROUP_15, 0xF /* Seq */);
             break;
-        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);
+        }
+
+        case STAC9220_NID_VOL_KNOB:
+        {
             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 0x17:
-            pNode->node.au32F02_param[0] = 0x12;
+        }
+
+        case STAC9220_NID_AMP_ADC0:
+        {
+            pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC0_MUX;
             goto adcvol_init;
-        case 0x18:
-            pNode->node.au32F02_param[0] = 0x13;
+        }
+
+        case STAC9220_NID_AMP_ADC1:
+        {
+            pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC1_MUX;
+
+            /* Fall through is intentional. */
         adcvol_init:
-            memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
-
-            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);
+
+            pNode->adcvol.u32F0c_param = 0;
+
+            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_BZERO(pNode->adcvol.B_params, AMPLIFIER_SIZE);
+            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;
-        case 0x19:
-            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0)
+        }
+
+        /*
+         * STAC9221 nodes.
+         */
+
+        case STAC9221_NID_ADAT_OUT:
+        {
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 3, 0)
                                            | CODEC_F00_09_CAP_DIGITAL
-                                           | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
+                                           | CODEC_F00_09_CAP_STEREO;
             break;
-        case 0x1A:
-            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0)
+        }
+
+        case STAC9221_NID_I2S_OUT:
+        {
+            pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 3, 0)
                                            | CODEC_F00_09_CAP_DIGITAL
-                                           | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
+                                           | CODEC_F00_09_CAP_STEREO;
             break;
-        case 0x1B:
+        }
+
+        case STAC9221_NID_PIN_I2S_OUT:
+        {
             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_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;
+                                           | 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 */);
             break;
+        }
+
         default:
-        break;
-    }
+            AssertMsgFailed(("Node %RU8 not implemented\n", uNID));
+            break;
+    }
+
     return VINF_SUCCESS;
 }
@@ -1213,15 +1436,24 @@
 static int stac9220Construct(PHDACODEC pThis)
 {
-    unconst(pThis->cTotalNodes) = 0x1C;
+    unconst(pThis->cTotalNodes) = STAC9221_NUM_NODES;
+
     pThis->pfnCodecNodeReset = stac9220ResetNode;
-    pThis->pfnDbgListNodes   = stac9220DbgNodes;
-    pThis->u16VendorId = 0x8384;
-    pThis->u16DeviceId = 0x7680;
-    pThis->u8BSKU = 0x76;
+
+    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->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);
@@ -1239,6 +1471,7 @@
     STAC9220WIDGET(Reserved);
 #undef STAC9220WIDGET
-    unconst(pThis->u8AdcVolsLineIn) = 0x17;
-    unconst(pThis->u8DacLineOut) = 0x3;
+
+    unconst(pThis->u8AdcVolsLineIn) = STAC9220_NID_AMP_ADC0;
+    unconst(pThis->u8DacLineOut)    = STAC9220_NID_DAC1;
 
     return VINF_SUCCESS;
@@ -1290,31 +1523,33 @@
  * Misc helpers.
  */
-static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL mt)
-{
-    uint32_t dir = AMPLIFIER_OUT;
-    ENMSOUNDSOURCE enmSrc;
-    switch (mt)
-    {
-        case PDMAUDIOMIXERCTL_PCM:
-            enmSrc = PO_INDEX;
-            dir = AMPLIFIER_OUT;
+static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
+{
+    uint8_t iDir;
+    switch (enmMixerCtl)
+    {
+        case PDMAUDIOMIXERCTL_VOLUME:
+        case PDMAUDIOMIXERCTL_FRONT:
+            iDir = AMPLIFIER_OUT;
             break;
         case PDMAUDIOMIXERCTL_LINE_IN:
-            enmSrc = PI_INDEX;
-            dir = AMPLIFIER_IN;
+        case PDMAUDIOMIXERCTL_MIC_IN:
+            iDir = AMPLIFIER_IN;
             break;
         default:
-            AssertMsgFailedReturn(("Invalid mixer control %ld\n", mt), VERR_INVALID_PARAMETER);
+            AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), VERR_INVALID_PARAMETER);
             break;
     }
 
-    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.
+    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;
+
+    /*
+     * 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
@@ -1324,5 +1559,6 @@
     rVol = (rVol + 1) * (2 * 255) / 256;
 
-    return pThis->pfnSetVolume(pThis->pHDAState, enmSrc, RT_BOOL(mute), lVol, rVol);
+    PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
+    return pThis->pfnMixerSetVolume(pThis->pHDAState, enmMixerCtl, &Vol);
 }
 
@@ -1426,5 +1662,5 @@
                             u8Index);
     else
-        LogRel2(("HDA: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
 
     return VINF_SUCCESS;
@@ -1454,5 +1690,5 @@
         pAmplifier = &pNode->adc.B_params;
     else
-        LogRel2(("HDA: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
+        LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
                  cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd)));
 
@@ -1488,5 +1724,5 @@
 
         if (CODEC_NID(cmd) == pThis->u8DacLineOut)
-            hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_PCM);
+            hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
     }
 
@@ -1531,5 +1767,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
     else
-        LogRel2(("HDA: Unhandled get pin control command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -1556,6 +1792,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
     else
-        LogRel2(("HDA: Unhandled set connection select control command: 0x%x (Payload=0x%x, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -1586,5 +1821,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
     else
-        LogRel2(("HDA: Unhandled get pin control command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -1614,6 +1849,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
     else
-        LogRel2(("HDA: Unhandled set pin control command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -1635,5 +1869,5 @@
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
-    else if ((cmd) == 1 /* AFG */)
+    else if ((cmd) == STAC9220_NID_AFG)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
     else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
@@ -1644,6 +1878,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
     else
-        LogRel2(("HDA: Unhandled get unsolicited enabled command: 0x%x (NID=0x%x [%RU8])\n",
-                 cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -1663,5 +1896,5 @@
     else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
-    else if (CODEC_NID(cmd) == 1 /* AFG */)
+    else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
     else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
@@ -1672,6 +1905,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
     else
-        LogRel2(("HDA: Unhandled set unsolicited enabled command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -1694,5 +1926,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
     else
-        LogRel2(("HDA: Unhandled get pin sense command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -1713,6 +1945,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
     else
-        LogRel2(("HDA: Unhandled set pin sense command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -1818,5 +2049,5 @@
         return VINF_SUCCESS;
     }
-    if (CODEC_NID(cmd) == 1 /* AFG */)
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
     else
@@ -1835,5 +2066,5 @@
     }
     uint32_t *pu32Reg;
-    if (CODEC_NID(cmd) == 0x1 /* AFG */)
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
     else
@@ -1874,6 +2105,6 @@
 {
     Assert(CODEC_CAD(cmd) == pThis->id);
-    Assert(CODEC_NID(cmd) == 1 /* AFG */);
-    if (   CODEC_NID(cmd) == 1 /* AFG */
+    Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
+    if (   CODEC_NID(cmd) == STAC9220_NID_AFG
         && pThis->pfnCodecNodeReset)
     {
@@ -1900,5 +2131,5 @@
     *pResp = 0;
 
-    if (CODEC_NID(cmd) == 1 /* AFG */)
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
     else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
@@ -1906,4 +2137,6 @@
     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;
@@ -1915,20 +2148,9 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
     else
-        LogRel2(("HDA: Unhandled get power state command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
-
-    return VINF_SUCCESS;
-}
-
-DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
-{
-    AssertPtr(pu32F05_param);
-    if (!pu32F05_param)
-        return;
-
-    bool fReset  = CODEC_F05_IS_RESET(*pu32F05_param);
-    bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
-    uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
-
-    *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
+        LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
+
+    LogFunc(("NID=0x%x, fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
+             CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_SET(*pResp), CODEC_F05_ACT(*pResp)));
+    return VINF_SUCCESS;
 }
 
@@ -1942,5 +2164,5 @@
 
     uint32_t *pu32Reg = NULL;
-    if (CODEC_NID(cmd) == 1 /* AFG */)
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
     else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
@@ -1948,4 +2170,6 @@
     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;
@@ -1957,45 +2181,71 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
     else
-        LogRel2(("HDA: Unhandled set power state command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (!pu32Reg)
         return VINF_SUCCESS;
 
-    bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
-    bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
-
-    if (CODEC_NID(cmd) != 1 /* AFG */)
-    {
-        /*
-         * We shouldn't propogate actual power state, which actual for AFG
-         */
+    bool    fReset  = CODEC_F05_IS_RESET (*pu32Reg);
+    bool    fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
+    uint8_t uPwrAct = CODEC_F05_ACT      (*pu32Reg);
+    uint8_t uPwrSet = CODEC_F05_SET      (*pu32Reg);
+    uint8_t uPwrCmd = CODEC_F05_SET      (cmd);
+
+    LogFunc(("[NID=0x%x] Cmd=D%RU8, Act=D%RU8, Set=D%RU8 (AFG Act=D%RU8, Set=D%RU8)\n",
+            CODEC_NID(cmd), uPwrCmd, uPwrAct, uPwrSet,
+            CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param),
+            CODEC_F05_SET(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param)));
+
+    const uint8_t uAFGPwrSet = CODEC_F05_SET(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param);
+
+    /* If this is the AFG node, PS-Act always matches the PS-Set power state.*/
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+    {
+        *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
+
+        /* Propagate to all other nodes under this AFG. */
+        LogFunc(("Propagating Set=D%RU8 to all nodes ...\n", 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, RT_MIN((uAFGPwrSet + 1), CODEC_F05_D3), \
+                                   uPwrCmd /* Always update PS-Set with command power state just received. */); \
+                LogFunc(("\t[NID=0x%x]: 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), adpopt 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,
-                                  CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param),
-                                  CODEC_F05_SET(cmd));
-    }
-
-    /* Propagate next power state only if AFG is on or verb modifies AFG power state */
-    if (   CODEC_NID(cmd) == 1 /* AFG */
-        || !CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param))
-    {
-        *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
-        if (   CODEC_NID(cmd) == 1 /* AFG */
-            && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
-        {
-            /* now we're powered on AFG and may propogate power states on nodes */
-            const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
-            while (*(++pu8NodeIndex))
-                codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].dac.u32F05_param);
-
-            pu8NodeIndex = &pThis->au8Adcs[0];
-            while (*(++pu8NodeIndex))
-                codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].adc.u32F05_param);
-
-            pu8NodeIndex = &pThis->au8DigInPins[0];
-            while (*(++pu8NodeIndex))
-                codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].digin.u32F05_param);
-        }
-    }
+                                  RT_MIN((uAFGPwrSet + 1), CODEC_F05_D3),
+                                  uPwrCmd /* Always update PS-Set with command power state just received. */);
+    }
+
+    if (pu32Reg)
+        hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
+
+    LogFunc(("[NID=0x%x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
+             CODEC_NID(cmd), fReset, fStopOk, CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
+
     return VINF_SUCCESS;
 }
@@ -2016,8 +2266,11 @@
     else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
         *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
-    else if (CODEC_NID(cmd) == 0x1A)
+    else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
     else
-        LogRel2(("HDA: Unhandled get stream ID command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
+
+    LogFlowFunc(("[NID0x%x] Stream ID is 0x%x\n",
+                 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(*pResp)));
 
     return VINF_SUCCESS;
@@ -2044,6 +2297,8 @@
         pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
     else
-        LogRel2(("HDA: Unhandled set stream ID command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
+
+    LogFlowFunc(("[NID0x%x] Setting new stream ID to 0x%x\n",
+                 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd)));
 
     if (pu32Addr)
@@ -2053,5 +2308,5 @@
 }
 
-/* F06 */
+/* A0 */
 static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
 {
@@ -2069,10 +2324,13 @@
     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: Unhandled get power state command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
-
-    return VINF_SUCCESS;
-}
-
+        LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%x: 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)
 {
@@ -2091,6 +2349,5 @@
         hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
     else
-        LogRel2(("HDA: Unhandled set converter format command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -2112,5 +2369,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
     else
-        LogRel2(("HDA: Unhandled get EAPD/BTL enable command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -2133,6 +2390,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
     else
-        LogRel2(("HDA: Unhandled set EAPD/BTL enable command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -2153,5 +2409,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
     else
-        LogRel2(("HDA: Unhandled get volume knob control command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -2170,6 +2426,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
     else
-        LogRel2(("HDA: Unhandled set volume control command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -2179,4 +2434,48 @@
 }
 
+/* F15 */
+static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
+{
+    if (!vrbIsValidNode(pThis, cmd, pResp))
+        return VINF_SUCCESS;
+
+    *pResp = 0;
+
+    return VINF_SUCCESS;
+}
+
+/* 715 */
+static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
+{
+    if (!vrbIsValidNode(pThis, cmd, pResp))
+        return VINF_SUCCESS;
+
+    *pResp = 0;
+
+    return VINF_SUCCESS;
+}
+
+/* F16 */
+static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
+{
+    if (!vrbIsValidNode(pThis, cmd, pResp))
+        return VINF_SUCCESS;
+
+    *pResp = 0;
+
+    return VINF_SUCCESS;
+}
+
+/* 716 */
+static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
+{
+    if (!vrbIsValidNode(pThis, cmd, pResp))
+        return VINF_SUCCESS;
+
+    *pResp = 0;
+
+    return VINF_SUCCESS;
+}
+
 /* F17 */
 static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
@@ -2188,8 +2487,8 @@
 
     /* Note: this is true for ALC885. */
-    if (CODEC_NID(cmd) == 0x1 /* AFG */)
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         *pResp = pThis->paNodes[1].afg.u32F17_param;
     else
-        LogRel2(("HDA: Unhandled get GPIO unsolisted command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get GPIO unsolisted command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -2205,9 +2504,8 @@
 
     uint32_t *pu32Reg = NULL;
-    if (CODEC_NID(cmd) == 1 /* AFG */)
+    if (CODEC_NID(cmd) == STAC9220_NID_AFG)
         pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
     else
-        LogRel2(("HDA: Unhandled set GPIO unsolisted command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set GPIO unsolisted command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -2238,5 +2536,5 @@
         *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
     else
-        LogRel2(("HDA: Unhandled get config command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled get config command for NID0x%x: 0x%x\n", CODEC_NID(cmd), cmd));
 
     return VINF_SUCCESS;
@@ -2259,6 +2557,5 @@
         pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
     else
-        LogRel2(("HDA: Unhandled set config command: 0x%x (Payload=%RU8, NID=0x%x [%RU8])\n",
-                 cmd, CODEC_VERB_PAYLOAD8(cmd), CODEC_NID(cmd)));
+        LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
 
     if (pu32Reg)
@@ -2346,4 +2643,8 @@
     { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl      },
     { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl      },
+    { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData            },
+    { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData            },
+    { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask      },
+    { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask      },
     { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted      },
     { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted      },
@@ -2357,4 +2658,5 @@
     { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier           },
     { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier           },
+    /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
 };
 
@@ -2581,6 +2883,4 @@
 {
     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
@@ -2588,10 +2888,9 @@
     {
         *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;
-    }
-
-    for (int i = 0; i < pThis->cVerbs; ++i)
+        AssertMsgFailed(("Unknown / invalid node 0x%x\n", CODEC_NID(cmd)));
+        return VINF_SUCCESS;
+    }
+
+    for (int i = 0; i < pThis->cVerbs; i++)
     {
         if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
@@ -2603,5 +2902,6 @@
 
     *pfn = vrbProcUnimplemented;
-    LogFlowFunc(("callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
+
+    LogFlowFunc(("[NID0x%x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
     return VINF_SUCCESS;
 }
@@ -2611,35 +2911,37 @@
  */
 
-/**
- *
- * 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)
+int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
 {
     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    int rc;
-    switch (enmSoundSource)
-    {
-        case PI_INDEX:
-            rc = pThis->pfnOpenIn(pThis->pHDAState,  "hda.in", PDMAUDIORECSOURCE_LINE_IN, pCfg);
+    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
+
+    int rc = VINF_SUCCESS;
+
+    switch (enmMixerCtl)
+    {
+        case PDMAUDIOMIXERCTL_LINE_IN:
+#ifdef VBOX_WITH_HDA_MIC_IN
+        case PDMAUDIOMIXERCTL_MIC_IN:
+#endif
+        {
+            pCfg->enmDir = PDMAUDIODIR_IN;
             break;
-#ifdef VBOX_WITH_HDA_MIC_IN
-        case MC_INDEX:
-            rc = pThis->pfnOpenIn(pThis->pHDAState,  "hda.mc", PDMAUDIORECSOURCE_MIC, pCfg);
+        }
+
+        case PDMAUDIOMIXERCTL_VOLUME:
+        case PDMAUDIOMIXERCTL_FRONT:
+        {
+            pCfg->enmDir = PDMAUDIODIR_OUT;
             break;
-#endif
-        case PO_INDEX:
-            rc = pThis->pfnOpenOut(pThis->pHDAState, "hda.out", pCfg);
+        }
+
+        default:
+            AssertMsgFailed(("Mixer control %ld not implemented\n", enmMixerCtl));
+            rc = VERR_NOT_IMPLEMENTED;
             break;
-
-        default:
-            AssertMsgFailed(("Index %ld not implemented\n", enmSoundSource));
-            rc = VERR_NOT_IMPLEMENTED;
-    }
+    }
+
+    if (RT_SUCCESS(rc))
+        rc = pThis->pfnMixerAddStream(pThis->pHDAState, enmMixerCtl, pCfg);
 
     LogFlowFuncLeaveRC(rc);
@@ -2647,7 +2949,12 @@
 }
 
+int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl)
+{
+    return VINF_SUCCESS;
+}
+
 int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
 {
-    AssertLogRelMsgReturn(pThis->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
+    AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
                           VERR_INTERNAL_ERROR);
     SSMR3PutU32(pSSM, pThis->cTotalNodes);
@@ -2715,7 +3022,7 @@
      */
     if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
-        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
+        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_FRONT);
     else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
-        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_PCM);
+        hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
     hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
 
@@ -2740,42 +3047,77 @@
 {
     AssertPtrReturn(pDevIns, 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->pfnLookup       = codecLookup;
+    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
+
+    pThis->id      = uLUN;
+    pThis->paVerbs = &g_aCodecVerbs[0];
+    pThis->cVerbs  = RT_ELEMENTS(g_aCodecVerbs);
+
 #ifdef DEBUG
     pThis->pfnDbgSelector  = codecDbgSelector;
     pThis->pfnDbgListNodes = codecDbgListNodes;
 #endif
+    pThis->pfnLookup       = codecLookup;
+
     int rc = stac9220Construct(pThis);
     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);
+    /* 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);
+
+    /* 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;
+    strmCfg.uHz           = 44100;
+    strmCfg.cChannels     = 2;
+    strmCfg.enmFormat     = AUD_FMT_S16;
+    strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+    /*
+     * Output streams.
+     */
+    strmCfg.enmDir = PDMAUDIODIR_OUT;
+
+    /* Front. */
+    strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+    rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_FRONT, &strmCfg);
+    AssertRC(rc);
+
+#ifdef VBOX_WITH_HDA_51_SURROUND
+    /* Center / LFE. */
+    strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
+    rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, &strmCfg);
+    AssertRC(rc);
+
+    /* Rear. */
+    strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
+    rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_REAR, &strmCfg);
+    AssertRC(rc);
+#endif
+
+    /*
+     * Input streams.
+     */
+    strmCfg.enmDir = PDMAUDIODIR_IN;
+
 #ifdef VBOX_WITH_HDA_MIC_IN
-    hdaCodecOpenStream(pThis, MC_INDEX, &pThis->strmCfg);
+    strmCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
+    rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_MIC_IN, &strmCfg);
+    AssertRC(rc);
 #endif
-    hdaCodecOpenStream(pThis, PO_INDEX, &pThis->strmCfg);
-
-    /* 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;
-
+    strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
+    rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_LINE_IN, &strmCfg);
+    AssertRC(rc);
+
+    /*
+     * Reset nodes.
+     */
     AssertPtr(pThis->paNodes);
     AssertPtr(pThis->pfnCodecNodeReset);
@@ -2784,8 +3126,14 @@
         pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
 
-    hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params,       PDMAUDIOMIXERCTL_PCM);
+    /*
+     * Set initial volume.
+     */
+    hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params,       PDMAUDIOMIXERCTL_FRONT);
     hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
-
-    return VINF_SUCCESS;
-}
-
+#ifdef VBOX_WITH_HDA_MIC_IN
+    #error "Implement mic-in support!"
+#endif
+
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.h	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.h	(revision 60353)
@@ -16,6 +16,6 @@
  */
 
-#ifndef DEV_CODEC_H
-#define DEV_CODEC_H
+#ifndef DEV_HDA_CODEC_H
+#define DEV_HDA_CODEC_H
 
 /** The ICH HDA (Intel) controller. */
@@ -39,6 +39,4 @@
 #define CODEC_RESPONSE_UNSOLICITED RT_BIT_64(34)
 
-
-#ifndef VBOX_WITH_HDA_CODEC_EMU
 typedef struct CODECVERB
 {
@@ -48,25 +46,11 @@
     PFNHDACODECVERBPROCESSOR pfn;
 } 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;
+union CODECNODE;
+typedef union CODECNODE CODECNODE, *PCODECNODE;
 
-typedef enum
-{
-    PI_INDEX = 0,    /**< PCM in */
-    PO_INDEX,        /**< PCM out */
-    MC_INDEX,        /**< Mic in */
-    LAST_INDEX
-} ENMSOUNDSOURCE;
-
+/**
+ * Structure for keeping a HDA codec state.
+ */
 typedef struct HDACODEC
 {
@@ -79,13 +63,8 @@
      * 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;
     int                     cVerbs;
-#else
-    PCODECEMU               pCodecBackend;
-#endif
+
     PCODECNODE              paNodes;
     /** Pointer to HDA state (controller) this
@@ -93,5 +72,5 @@
     PHDASTATE               pHDAState;
     bool                    fInReset;
-#ifndef VBOX_WITH_HDA_CODEC_EMU
+
     const uint8_t           cTotalNodes;
     const uint8_t          *au8Ports;
@@ -110,11 +89,9 @@
     const uint8_t           u8AdcVolsLineIn;
     const uint8_t           u8DacLineOut;
-#endif
+
     /** Callbacks to the HDA controller, mostly used for multiplexing to the various host backends. */
-    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));
+    DECLR3CALLBACKMEMBER(int, pfnMixerAddStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg));
+    DECLR3CALLBACKMEMBER(int, pfnMixerRemoveStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl));
+    DECLR3CALLBACKMEMBER(int, pfnMixerSetVolume, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol));
     /** Callbacks by codec implementation. */
     DECLR3CALLBACKMEMBER(int, pfnLookup, (PHDACODEC pThis, uint32_t verb, PPFNHDACODECVERBPROCESSOR));
@@ -130,5 +107,6 @@
 int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM);
 int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion);
-int hdaCodecOpenStream(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, PPDMAUDIOSTREAMCFG pCfg);
+int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg);
+int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl);
 
 #define HDA_SSM_VERSION   6
@@ -143,13 +121,4 @@
 #define HDA_SSM_VERSION_1 1
 
-# 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
+#endif /* DEV_HDA_CODEC_H */
 
Index: /trunk/src/VBox/Devices/Audio/DevIchHdaCommon.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchHdaCommon.h	(revision 60353)
+++ /trunk/src/VBox/Devices/Audio/DevIchHdaCommon.h	(revision 60353)
@@ -0,0 +1,525 @@
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
+/* $Id$ */
+/** @file
+ * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
+ */
+
+/*
+ * Copyright (C) 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 DEV_HDA_COMMON_H
+#define DEV_HDA_COMMON_H
+
+#define HDA_SDFMT_NON_PCM_SHIFT                            15
+#define HDA_SDFMT_NON_PCM_MASK                             0x1
+#define HDA_SDFMT_BASE_RATE_SHIFT                          14
+#define HDA_SDFMT_BASE_RATE_MASK                           0x1
+#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 HDA_SDFMT_CHANNELS_MASK                            0xF
+
+#define HDA_SDFMT_TYPE                                     RT_BIT(15)
+#define HDA_SDFMT_TYPE_PCM                                 (0)
+#define HDA_SDFMT_TYPE_NON_PCM                             (1)
+
+#define HDA_SDFMT_BASE                                     RT_BIT(14)
+#define HDA_SDFMT_BASE_48KHZ                               (0)
+#define HDA_SDFMT_BASE_44KHZ                               (1)
+
+#define HDA_SDFMT_MULT_1X                                  (0)
+#define HDA_SDFMT_MULT_2X                                  (1)
+#define HDA_SDFMT_MULT_3X                                  (2)
+#define HDA_SDFMT_MULT_4X                                  (3)
+
+#define HDA_SDFMT_DIV_1X                                   (0)
+#define HDA_SDFMT_DIV_2X                                   (1)
+#define HDA_SDFMT_DIV_3X                                   (2)
+#define HDA_SDFMT_DIV_4X                                   (3)
+#define HDA_SDFMT_DIV_5X                                   (4)
+#define HDA_SDFMT_DIV_6X                                   (5)
+#define HDA_SDFMT_DIV_7X                                   (6)
+#define HDA_SDFMT_DIV_8X                                   (7)
+
+#define HDA_SDFMT_8_BIT                                    (0)
+#define HDA_SDFMT_16_BIT                                   (1)
+#define HDA_SDFMT_20_BIT                                   (2)
+#define HDA_SDFMT_24_BIT                                   (3)
+#define HDA_SDFMT_32_BIT                                   (4)
+
+#define HDA_SDFMT_CHAN_MONO                                (0)
+#define HDA_SDFMT_CHAN_STEREO                              (1)
+
+/* Emits a SDnFMT register format. */
+/* Also being used in the codec's converter format. */
+#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan)    \
+    (  (((_afNonPCM)  & HDA_SDFMT_NON_PCM_MASK)   << HDA_SDFMT_NON_PCM_SHIFT)   \
+     | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
+     | (((_aMult)     & HDA_SDFMT_MULT_MASK)      << HDA_SDFMT_MULT_SHIFT)      \
+     | (((_aDiv)      & HDA_SDFMT_DIV_MASK)       << HDA_SDFMT_DIV_SHIFT)       \
+     | (((_aBits)     & HDA_SDFMT_BITS_MASK)      << HDA_SDFMT_BITS_SHIFT)      \
+     | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
+
+#endif /* DEV_HDA_COMMON_H */
+
Index: /trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 60353)
@@ -72,31 +72,19 @@
 int drvAudioAddHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
 {
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
-    PPDMAUDIOHSTSTRMOUT pHstStrmOut;
+    AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
 
     int rc;
-    if (   conf.fixed_out.enabled /** @todo Get rid of these settings! */
-        && conf.fixed_out.greedy)
+
+    PPDMAUDIOHSTSTRMOUT pHstStrmOut = drvAudioFindSpecificOut(pThis, NULL, pCfg);
+    if (!pHstStrmOut)
     {
         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_FAILURE(rc))
+            pHstStrmOut = drvAudioFindAnyHstOut(pThis, NULL /* pHstStrmOut */);
+    }
+
+    rc = pHstStrmOut ? VINF_SUCCESS : rc;
 
     if (RT_SUCCESS(rc))
@@ -106,4 +94,5 @@
 }
 
+#ifndef VBOX_AUDIO_TESTCASE
 static PDMAUDIOFMT drvAudioGetConfFormat(PCFGMNODE pCfgHandle, const char *pszKey,
                                          PDMAUDIOFMT enmDefault, bool *pfDefault)
@@ -272,4 +261,5 @@
     return VINF_SUCCESS;
 }
+#endif /* !VBOX_AUDIO_TESTCASE */
 
 static bool drvAudioStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
@@ -301,9 +291,4 @@
     fValid |= pCfg->uHz > 0;
 
-#ifdef DEBUG
-    drvAudioStreamCfgPrint(pCfg);
-#endif
-
-    LogFlowFunc(("pCfg=%p, fValid=%RTbool\n", pCfg, fValid));
     return fValid;
 }
@@ -828,24 +813,7 @@
                                 PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
 {
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    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)));
+    AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
 
     PPDMAUDIOGSTSTRMOUT pGstStrmOut =
@@ -861,5 +829,5 @@
      */
     PPDMAUDIOHSTSTRMOUT pHstStrmOut;
-    int rc = drvAudioAddHstOut(pThis, pszName, pBackendCfg, &pHstStrmOut);
+    int rc = drvAudioAddHstOut(pThis, pszName, pCfg, &pHstStrmOut);
     if (RT_FAILURE(rc))
     {
@@ -893,23 +861,7 @@
                                       PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
 {
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    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)));
+    AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
 
     PPDMAUDIOGSTSTRMIN pGstStrmIn = (PPDMAUDIOGSTSTRMIN)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMIN));
@@ -921,5 +873,5 @@
      */
     PPDMAUDIOHSTSTRMIN pHstStrmIn;
-    int rc = drvAudioHstInAdd(pThis, pszName, pBackendCfg, enmRecSource, &pHstStrmIn);
+    int rc = drvAudioHstInAdd(pThis, pszName, pCfg, enmRecSource, &pHstStrmIn);
     if (RT_FAILURE(rc))
     {
@@ -1716,46 +1668,4 @@
 }
 
-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? */
-};
-
 static DECLCALLBACK(int) drvAudioInit(PCFGMNODE pCfgHandle, PPDMDRVINS pDrvIns)
 {
@@ -1774,18 +1684,6 @@
 
     int rc = RTCritSectInit(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-    {
-        rc = drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options, RT_ELEMENTS(audio_options));
-        /** @todo Check for invalid options? */
-
-        pThis->cStreamsFreeOut = conf.fixed_out.cStreams;
-        pThis->cStreamsFreeIn  = conf.fixed_in.cStreams;
-
-        if (!pThis->cStreamsFreeOut)
-            pThis->cStreamsFreeOut = 1;
-
-        if (!pThis->cStreamsFreeIn)
-            pThis->cStreamsFreeIn = 1;
-    }
+
+    /** @todo Add audio driver options. */
 
     /*
@@ -1964,6 +1862,5 @@
 
 static DECLCALLBACK(int) drvAudioCreateIn(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
-                                          PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
-                                          PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
+                                          PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
 {
     AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
@@ -1973,4 +1870,6 @@
     AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
 
+    Assert(pCfg->enmDir == PDMAUDIODIR_IN);
+
     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
 
@@ -1987,57 +1886,9 @@
     }
 
-    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)
+    if (RT_SUCCESS(rc))
+    {
+        PPDMAUDIOGSTSTRMIN pGstStrmIn;
+        rc = drvAudioCreateStreamPairIn(pThis, pszName, pCfg->DestSource.Source, pCfg, &pGstStrmIn);
+        if (RT_SUCCESS(rc))
             *ppGstStrmIn = pGstStrmIn;
     }
@@ -2059,4 +1910,6 @@
     AssertPtrReturn(ppGstStrmOut, VERR_INVALID_POINTER);
 
+    Assert(pCfg->enmDir == PDMAUDIODIR_OUT);
+
     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
 
@@ -2073,84 +1926,10 @@
     }
 
-    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
-    {
+    if (RT_SUCCESS(rc))
+    {
+        PPDMAUDIOGSTSTRMOUT pGstStrmOut;
         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)
+        if (RT_SUCCESS(rc))
             *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
     }
 
@@ -2377,5 +2156,5 @@
     }
 
-#ifdef DEBUG_andy
+#ifndef VBOX_AUDIO_TESTCASE
     CFGMR3Dump(pCfgHandle);
 #endif
Index: /trunk/src/VBox/Devices/Audio/DrvAudio.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudio.h	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DrvAudio.h	(revision 60353)
@@ -154,51 +154,4 @@
 int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps);
 
-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? */
-};
 #endif /* DRV_AUDIO_H */
 
Index: /trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 60353)
@@ -71,5 +71,5 @@
         case PDMAUDIORECSOURCE_VIDEO:   return "Video";
         case PDMAUDIORECSOURCE_AUX:     return "AUX";
-        case PDMAUDIORECSOURCE_LINE_IN: return "Line In";
+        case PDMAUDIORECSOURCE_LINE: return "Line In";
         case PDMAUDIORECSOURCE_PHONE:   return "Phone";
         default:
Index: /trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 60353)
@@ -907,5 +907,5 @@
             }
 
-            case PDMAUDIORECSOURCE_LINE_IN:
+            case PDMAUDIORECSOURCE_LINE:
             default:
                 /* Try opening the default device (NULL). */
Index: /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
===================================================================
--- /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp	(revision 60352)
+++ /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp	(revision 60353)
@@ -1902,10 +1902,10 @@
 
     GEN_CHECK_SIZE(HDAINPUTSTREAM);
-    GEN_CHECK_OFF(HDAINPUTSTREAM, pStrmIn);
-    GEN_CHECK_OFF(HDAINPUTSTREAM, phStrmIn);
+    GEN_CHECK_OFF(HDAINPUTSTREAM, pGstStrm);
+    GEN_CHECK_OFF(HDAINPUTSTREAM, pMixStrm);
 
     GEN_CHECK_SIZE(HDAOUTPUTSTREAM);
-    GEN_CHECK_OFF(HDAOUTPUTSTREAM, pStrmOut);
-    GEN_CHECK_OFF(HDAOUTPUTSTREAM, phStrmOut);
+    GEN_CHECK_OFF(HDAOUTPUTSTREAM, pGstStrm);
+    GEN_CHECK_OFF(HDAOUTPUTSTREAM, pMixStrm);
 
     GEN_CHECK_SIZE(HDADRIVER);
@@ -1917,6 +1917,8 @@
     GEN_CHECK_OFF(HDADRIVER, pConnector);
     GEN_CHECK_OFF(HDADRIVER, LineIn);
+#ifdef VBOX_WITH_HDA_MIC_IN
     GEN_CHECK_OFF(HDADRIVER, MicIn);
-    GEN_CHECK_OFF(HDADRIVER, Out);
+#endif
+    GEN_CHECK_OFF(HDADRIVER, Front);
 
     GEN_CHECK_SIZE(HDABDLESTATE);
@@ -1937,5 +1939,5 @@
 
     GEN_CHECK_SIZE(HDASTREAM);
-    GEN_CHECK_OFF(HDASTREAM, u8Strm);
+    GEN_CHECK_OFF(HDASTREAM, u8SD);
     GEN_CHECK_OFF(HDASTREAM, u64BDLBase);
     GEN_CHECK_OFF(HDASTREAM, u16FMT);
@@ -1952,8 +1954,7 @@
     GEN_CHECK_OFF(HDASTATE, MMIOBaseAddr);
     GEN_CHECK_OFF(HDASTATE, au32Regs[0]);
-    GEN_CHECK_OFF(HDASTATE, au32Regs[HDA_NREGS]);
-    GEN_CHECK_OFF(HDASTATE, StrmStLineIn);
-    GEN_CHECK_OFF(HDASTATE, StrmStOut);
-    GEN_CHECK_OFF(HDASTATE, StrmStMicIn);
+    GEN_CHECK_OFF(HDASTATE, au32Regs[HDA_NUM_REGS]);
+    GEN_CHECK_OFF(HDASTATE, aStreams);
+    GEN_CHECK_OFF(HDASTATE, aTags);
     GEN_CHECK_OFF(HDASTATE, u64CORBBase);
     GEN_CHECK_OFF(HDASTATE, u64RIRBBase);
@@ -1977,12 +1978,22 @@
     GEN_CHECK_OFF(HDASTATE, StatBytesRead);
     GEN_CHECK_OFF(HDASTATE, StatBytesWritten);
-#endif
+#endif /* VBOX_WITH_STATISTICS */
     GEN_CHECK_OFF(HDASTATE, pCodec);
     GEN_CHECK_OFF(HDASTATE, lstDrv);
     GEN_CHECK_OFF(HDASTATE, pMixer);
+    GEN_CHECK_OFF(HDASTATE, pSinkFront);
+#ifdef VBOX_WITH_HDA_51_SURROUND
+    GEN_CHECK_OFF(HDASTATE, pSinkCenterLFE);
+    GEN_CHECK_OFF(HDASTATE, pSinkRear);
+#endif
     GEN_CHECK_OFF(HDASTATE, pSinkLineIn);
+#ifdef VBOX_WITH_HDA_MIC_IN
     GEN_CHECK_OFF(HDASTATE, pSinkMicIn);
+#endif
     GEN_CHECK_OFF(HDASTATE, u64BaseTS);
     GEN_CHECK_OFF(HDASTATE, u8RespIntCnt);
+#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
+    GEN_CHECK_OFF(HDASTATE, pCircBuf);
+#endif
 
 #ifdef VBOX_WITH_NVME_IMPL
