Index: /trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 82450)
@@ -24,7 +24,4 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
-#ifdef DEBUG_bird
-# define RT_NO_STRICT /* I'm tried of this crap asserting on save and restore of Maverics guests.  */
-#endif
 #define LOG_GROUP LOG_GROUP_DEV_HDA
 #include <VBox/log.h>
@@ -219,6 +216,8 @@
     /** Node for storing this driver in our device driver list of HDASTATE. */
     RTLISTNODER3                       Node;
-    /** Pointer to HDA controller (state). */
-    R3PTRTYPE(PHDASTATE)               pHDAState;
+    /** Pointer to shared HDA device state. */
+    R3PTRTYPE(PHDASTATE)               pHDAStateShared;
+    /** Pointer to the ring-3 HDA device state. */
+    R3PTRTYPE(PHDASTATER3)             pHDAStateR3;
     /** Driver flags. */
     PDMAUDIODRVFLAGS                   fFlags;
@@ -254,5 +253,5 @@
 #ifndef VBOX_DEVICE_STRUCT_TESTCASE
 #ifdef IN_RING3
-static void hdaR3GCTLReset(PHDASTATE pThis);
+static void hdaR3GCTLReset(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC);
 #endif
 
@@ -317,6 +316,6 @@
  */
 #ifdef IN_RING3
-static int                        hdaR3AddStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg);
-static int                        hdaR3RemoveStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg);
+static int                        hdaR3AddStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg);
+static int                        hdaR3RemoveStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg);
 # ifdef HDA_USE_DMA_ACCESS_HANDLER
 static DECLCALLBACK(VBOXSTRICTRC) hdaR3DmaAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys,
@@ -331,5 +330,5 @@
  */
 #ifdef IN_RING3
-static int hdaR3MixerAddDrvStream(PHDASTATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg, PHDADRIVER pDrv);
+static int hdaR3MixerAddDrvStream(PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg, PHDADRIVER pDrv);
 #endif
 /** @} */
@@ -564,7 +563,9 @@
  * audio periods but did not have the chance to issue their (pending) interrupts yet.
  *
- * @param   pThis               The HDA device state.
- */
-static void hdaR3ReschedulePendingInterrupts(PHDASTATE pThis)
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
+ */
+static void hdaR3ReschedulePendingInterrupts(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
 {
     bool fInterrupt = false;
@@ -572,11 +573,8 @@
     for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
     {
-        PHDASTREAM pStream = hdaGetStreamFromSD(pThis, i);
-        if (!pStream)
-            continue;
-
-        if (   hdaR3StreamPeriodIsComplete    (&pStream->State.Period)
+        PHDASTREAM pStream = &pThis->aStreams[i];
+        if (   hdaR3StreamPeriodIsComplete(    &pStream->State.Period)
             && hdaR3StreamPeriodNeedsInterrupt(&pStream->State.Period)
-            && hdaR3WalClkSet(pThis, hdaR3StreamPeriodGetAbsElapsedWalClk(&pStream->State.Period), false /* fForce */))
+            && hdaR3WalClkSet(pThis, pThisCC, hdaR3StreamPeriodGetAbsElapsedWalClk(&pStream->State.Period), false /* fForce */))
         {
             fInterrupt = true;
@@ -587,5 +585,5 @@
     LogFunc(("fInterrupt=%RTbool\n", fInterrupt));
 
-    HDA_PROCESS_INTERRUPT(pThis->pDevInsR3, pThis);
+    HDA_PROCESS_INTERRUPT(pDevIns, pThis);
 }
 #endif /* IN_RING3 */
@@ -703,5 +701,7 @@
  *
  * @returns IPRT status code.
- * @param   pThis               HDA state.
+ *
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state.
  * @param   fLocal              Specify true to synchronize HDA state's CORB buffer with the device state,
  *                              or false to synchronize the device state's RIRB buffer with the HDA state.
@@ -709,5 +709,5 @@
  * @todo r=andy Break this up into two functions?
  */
-static int hdaR3CmdSync(PHDASTATE pThis, bool fLocal)
+static int hdaR3CmdSync(PPDMDEVINS pDevIns, PHDASTATE pThis, bool fLocal)
 {
     int rc = VINF_SUCCESS;
@@ -716,5 +716,4 @@
         if (pThis->u64CORBBase)
         {
-            AssertPtr(pThis->pu32CorbBuf);
             Assert(pThis->cbCorbBuf);
 
@@ -722,5 +721,6 @@
  *        the CORB and PDMDevHlpPCIPhysWrite with RIRB below.  There are
  *        similar unexplained inconsistencies in DevHDACommon.cpp. */
-            rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
+            rc = PDMDevHlpPhysRead(pDevIns, pThis->u64CORBBase, pThis->au32CorbBuf,
+                                   RT_MIN(pThis->cbCorbBuf, sizeof(pThis->au32CorbBuf)));
             Log(("hdaR3CmdSync/CORB: read %RGp LB %#x (%Rrc)\n", pThis->u64CORBBase, pThis->cbCorbBuf, rc));
             AssertRCReturn(rc, rc);
@@ -731,9 +731,9 @@
         if (pThis->u64RIRBBase)
         {
-            AssertPtr(pThis->pu64RirbBuf);
             Assert(pThis->cbRirbBuf);
 
-            rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf);
-            Log(("hdaR3CmdSync/RIRB: phys read %RGp LB %#x (%Rrc)\n", pThis->u64RIRBBase, pThis->pu64RirbBuf, rc));
+            rc = PDMDevHlpPCIPhysWrite(pDevIns, pThis->u64RIRBBase, pThis->au64RirbBuf,
+                                       RT_MIN(pThis->cbRirbBuf, sizeof(pThis->au64RirbBuf)));
+            Log(("hdaR3CmdSync/RIRB: phys read %RGp LB %#x (%Rrc)\n", pThis->u64RIRBBase, pThis->cbRirbBuf, rc));
             AssertRCReturn(rc, rc);
         }
@@ -789,14 +789,12 @@
  * This will invoke the HDA codec verb dispatcher.
  *
- * @returns IPRT status code.
- * @param   pThis               HDA state.
- */
-static int hdaR3CORBCmdProcess(PHDASTATE pThis)
-{
-    uint8_t corbRp = HDA_REG(pThis, CORBRP);
-    uint8_t corbWp = HDA_REG(pThis, CORBWP);
-    uint8_t rirbWp = HDA_REG(pThis, RIRBWP);
-
-    Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", corbRp, corbWp, rirbWp));
+ * @returns VBox status code suitable for MMIO write return.
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
+ */
+static int hdaR3CORBCmdProcess(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
+{
+    Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
 
     if (!(HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA))
@@ -808,27 +806,37 @@
     Assert(pThis->cbCorbBuf);
 
-    int rc = hdaR3CmdSync(pThis, true /* Sync from guest */);
+    int rc = hdaR3CmdSync(pDevIns, pThis, true /* Sync from guest */);
     AssertRCReturn(rc, rc);
 
+    /*
+     * Prepare local copies of relevant registers.
+     */
     uint16_t cIntCnt = HDA_REG(pThis, RINTCNT) & 0xff;
-
     if (!cIntCnt) /* 0 means 256 interrupts. */
         cIntCnt = HDA_MAX_RINTCNT;
 
-    Log3Func(("START CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n",
-              corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
-
+    uint32_t const cCorbEntries = RT_MIN(RT_MAX(pThis->cbCorbBuf, 1), sizeof(pThis->au32CorbBuf)) / HDA_CORB_ELEMENT_SIZE;
+    uint8_t const  corbWp       = HDA_REG(pThis, CORBWP) % cCorbEntries;
+    uint8_t        corbRp       = HDA_REG(pThis, CORBRP);
+    uint8_t        rirbWp       = HDA_REG(pThis, RIRBWP);
+
+    /*
+     * The loop.
+     */
+    Log3Func(("START CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n", corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
     while (corbRp != corbWp)
     {
-        corbRp = (corbRp + 1) % (pThis->cbCorbBuf / HDA_CORB_ELEMENT_SIZE); /* Advance +1 as the first command(s) are at CORBWP + 1. */
-
-        uint32_t uCmd  = pThis->pu32CorbBuf[corbRp];
+        /* Fetch the command from the CORB. */
+        corbRp = (corbRp + 1) /* Advance +1 as the first command(s) are at CORBWP + 1. */ % cCorbEntries;
+        uint32_t const uCmd = pThis->au32CorbBuf[corbRp];
+
+        /*
+         * Execute the command.
+         */
         uint64_t uResp = 0;
-
-        rc = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp);
+        rc = pThisCC->pCodec->pfnLookup(pThisCC->pCodec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp);
         if (RT_FAILURE(rc))
             LogFunc(("Codec lookup failed with rc=%Rrc\n", rc));
-
-        Log3Func(("Codec verb %08x -> response %016lx\n", uCmd, uResp));
+        Log3Func(("Codec verb %08x -> response %016RX64\n", uCmd, uResp));
 
         if (   (uResp & CODEC_RESPONSE_UNSOLICITED)
@@ -837,18 +845,24 @@
             LogFunc(("Unexpected unsolicited response.\n"));
             HDA_REG(pThis, CORBRP) = corbRp;
-
-            /** @todo r=andy No CORB/RIRB syncing to guest required in that case? */
-            return rc;
-        }
-
+            /** @todo r=andy No RIRB syncing to guest required in that case? */
+            /** @todo r=bird: Why isn't RIRBWP updated here.  The response might come
+             *        after already processing several commands, can't it?  (When you think
+             *        about it, it is bascially the same question as Andy is asking.) */
+            return VINF_SUCCESS;
+        }
+
+        /*
+         * Store the response in the RIRB.
+         */
+        AssertCompile(HDA_RIRB_SIZE == RT_ELEMENTS(pThis->au64RirbBuf));
         rirbWp = (rirbWp + 1) % HDA_RIRB_SIZE;
-
-        pThis->pu64RirbBuf[rirbWp] = uResp;
-
+        pThis->au64RirbBuf[rirbWp] = uResp;
+
+        /*
+         * Send interrupt if needed.
+         */
+        bool fSendInterrupt = false;
         pThis->u16RespIntCnt++;
-
-        bool fSendInterrupt = false;
-
-        if (pThis->u16RespIntCnt == cIntCnt) /* Response interrupt count reached? */
+        if (pThis->u16RespIntCnt >= cIntCnt) /* Response interrupt count reached? */
         {
             pThis->u16RespIntCnt = 0; /* Reset internal interrupt response counter. */
@@ -856,5 +870,4 @@
             Log3Func(("Response interrupt count reached (%RU16)\n", pThis->u16RespIntCnt));
             fSendInterrupt = true;
-
         }
         else if (corbRp == corbWp) /* Did we reach the end of the current command buffer? */
@@ -863,5 +876,4 @@
             fSendInterrupt = true;
         }
-
         if (fSendInterrupt)
         {
@@ -869,21 +881,21 @@
             {
                 HDA_REG(pThis, RIRBSTS) |= HDA_RIRBSTS_RINTFL;
-
-                rc = HDA_PROCESS_INTERRUPT(pThis->pDevInsR3, pThis);
+                HDA_PROCESS_INTERRUPT(pDevIns, pThis);
             }
         }
     }
 
-    Log3Func(("END CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n",
-              corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
-
+    /*
+     * Put register locals back.
+     */
+    Log3Func(("END CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n", corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
     HDA_REG(pThis, CORBRP) = corbRp;
     HDA_REG(pThis, RIRBWP) = rirbWp;
 
-    rc = hdaR3CmdSync(pThis, false /* Sync to guest */);
-    AssertRCReturn(rc, rc);
-
-    if (RT_FAILURE(rc))
-        AssertRCReturn(rc, rc);
+    /*
+     * Write out the response.
+     */
+    rc = hdaR3CmdSync(pDevIns, pThis, false /* Sync to guest */);
+    AssertRC(rc);
 
     return rc;
@@ -989,5 +1001,5 @@
         HDA_REG(pThis, GCTL) &= ~HDA_GCTL_CRST;
 
-        hdaR3GCTLReset(pThis);
+        hdaR3GCTLReset(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns,  PHDASTATER3));
 #else
         return VINF_IOM_R3_MMIO_WRITE;
@@ -1032,24 +1044,28 @@
 /**
  * Returns the current maximum value the wall clock counter can be set to.
+ *
  * This maximum value depends on all currently handled HDA streams and their own current timing.
  *
  * @return  Current maximum value the wall clock counter can be set to.
- * @param   pThis               HDA state.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
  *
  * @remark  Does not actually set the wall clock counter.
- */
-static uint64_t hdaR3WalClkGetMax(PHDASTATE pThis)
+ *
+ * @todo r=bird: This function is in the wrong file.
+ */
+static uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)
 {
     const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
-    const uint64_t u64FrontAbsWalClk  = pThis->SinkFront.pStream
-                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThis->SinkFront.pStream->State.Period) : 0;
+    const uint64_t u64FrontAbsWalClk  = pThisCC->SinkFront.pStreamShared
+                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period)  : 0;
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
 #  error "Implement me!"
 # endif
-    const uint64_t u64LineInAbsWalClk = pThis->SinkLineIn.pStream
-                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThis->SinkLineIn.pStream->State.Period) : 0;
+    const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared
+                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;
 # ifdef VBOX_WITH_HDA_MIC_IN
-    const uint64_t u64MicInAbsWalClk  = pThis->SinkMicIn.pStream
-                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThis->SinkMicIn.pStream->State.Period) : 0;
+    const uint64_t u64MicInAbsWalClk  = pThisCC->SinkMicIn.pStreamShared
+                                      ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period)  : 0;
 # endif
 
@@ -1078,5 +1094,5 @@
     *pu32Value = RT_LO_U32(u64WalClkCur);
 
-    Log3Func(("%RU32 (max @ %RU64)\n", *pu32Value, hdaR3WalClkGetMax(pThis)));
+    Log3Func(("%RU32 (max @ %RU64)\n", *pu32Value, hdaR3WalClkGetMax(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3))));
     return VINF_SUCCESS;
 #else
@@ -1094,10 +1110,6 @@
         if (pThis->cbCorbBuf)
         {
-#ifdef IN_RING3
-            AssertPtr(pThis->pu32CorbBuf);
-            RT_BZERO(pThis->pu32CorbBuf, pThis->cbCorbBuf);
-#else
+            RT_ZERO(pThis->au32CorbBuf);
             return VINF_IOM_R3_MMIO_WRITE;
-#endif
         }
 
@@ -1119,5 +1131,5 @@
 
     if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Start DMA engine. */
-        rc = hdaR3CORBCmdProcess(pThis);
+        rc = hdaR3CORBCmdProcess(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));
     else
         LogFunc(("CORB DMA not running, skipping\n"));
@@ -1132,5 +1144,4 @@
 static VBOXSTRICTRC hdaRegWriteCORBSIZE(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-#ifdef IN_RING3
     RT_NOREF(pDevIns, iReg);
 
@@ -1159,9 +1170,9 @@
 
         uint32_t cbCorbBuf = cEntries * HDA_CORB_ELEMENT_SIZE;
-        Assert(cbCorbBuf <= HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE); /* Paranoia. */
+        Assert(cbCorbBuf <= sizeof(pThis->au32CorbBuf)); /* paranoia */
 
         if (cbCorbBuf != pThis->cbCorbBuf)
         {
-            RT_BZERO(pThis->pu32CorbBuf, HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE); /* Clear CORB when setting a new size. */
+            RT_ZERO(pThis->au32CorbBuf); /* Clear CORB when setting a new size. */
             pThis->cbCorbBuf = cbCorbBuf;
         }
@@ -1174,4 +1185,23 @@
         LogFunc(("CORB DMA is (still) running, skipping\n"));
     return VINF_SUCCESS;
+}
+
+static VBOXSTRICTRC hdaRegWriteCORBSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+{
+    RT_NOREF(pDevIns, iReg);
+
+    uint32_t v = HDA_REG(pThis, CORBSTS);
+    HDA_REG(pThis, CORBSTS) &= ~(v & u32Value);
+
+    return VINF_SUCCESS;
+}
+
+static VBOXSTRICTRC hdaRegWriteCORBWP(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+{
+#ifdef IN_RING3
+    VBOXSTRICTRC rc = hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
+    AssertRCSuccess(VBOXSTRICTRC_VAL(rc));
+
+    return hdaR3CORBCmdProcess(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));
 #else
     RT_NOREF(pDevIns, pThis, iReg, u32Value);
@@ -1180,37 +1210,15 @@
 }
 
-static VBOXSTRICTRC hdaRegWriteCORBSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-    RT_NOREF(pDevIns, iReg);
-
-    uint32_t v = HDA_REG(pThis, CORBSTS);
-    HDA_REG(pThis, CORBSTS) &= ~(v & u32Value);
-
-    return VINF_SUCCESS;
-}
-
-static VBOXSTRICTRC hdaRegWriteCORBWP(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+static VBOXSTRICTRC hdaRegWriteSDCBL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+{
+    return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
+}
+
+static VBOXSTRICTRC hdaRegWriteSDCTL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
 #ifdef IN_RING3
-    VBOXSTRICTRC rc = hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
-    AssertRCSuccess(VBOXSTRICTRC_VAL(rc));
-
-    return hdaR3CORBCmdProcess(pThis);
-#else
-    RT_NOREF(pDevIns, pThis, iReg, u32Value);
-    return VINF_IOM_R3_MMIO_WRITE;
-#endif
-}
-
-static VBOXSTRICTRC hdaRegWriteSDCBL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-    return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
-}
-
-static VBOXSTRICTRC hdaRegWriteSDCTL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#ifdef IN_RING3
-    /* Get the stream descriptor. */
+    /* Get the stream descriptor number. */
     const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
+    AssertReturn(uSD < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
 
     /*
@@ -1221,12 +1229,12 @@
      * 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;
-    ASSERT_GUEST_MSG_RETURN(uTag < RT_ELEMENTS(pThis->aTags),
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    uint8_t     uTag    = (u32Value >> HDA_SDCTL_NUM_SHIFT) & HDA_SDCTL_NUM_MASK;
+    ASSERT_GUEST_MSG_RETURN(uTag < RT_ELEMENTS(pThisCC->aTags),
                             ("SD%RU8: Invalid stream tag %RU8 (u32Value=%#x)!\n", uSD, uTag, u32Value),
                             VINF_SUCCESS /* Always return success to the MMIO handler. */);
 
-    PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
-    ASSERT_GUEST_LOGREL_MSG_RETURN(pStream, ("Guest tried writing SDCTL (0x%x) to unhandled stream #%RU8\n", u32Value, uSD),
-                                   VINF_SUCCESS /* Always return success to the MMIO handler. */);
+    PHDASTREAM   const pStreamShared = &pThis->aStreams[uSD];
+    PHDASTREAMR3 const pStreamR3     = &pThisCC->aStreams[uSD];
 
     const bool fRun      = RT_BOOL(u32Value & HDA_SDCTL_RUN);
@@ -1242,5 +1250,5 @@
     {
         DEVHDA_UNLOCK(pDevIns, pThis);
-        DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStream, VINF_IOM_R3_MMIO_WRITE);
+        DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStreamShared, VINF_IOM_R3_MMIO_WRITE);
     }
 
@@ -1256,5 +1264,5 @@
 
         /* Exit reset state. */
-        ASMAtomicXchgBool(&pStream->State.fInReset, false);
+        ASMAtomicXchgBool(&pStreamShared->State.fInReset, false);
 
         /* Report that we're done resetting this stream by clearing SRST. */
@@ -1270,18 +1278,18 @@
         LogFunc(("[SD%RU8] Reset enter\n", uSD));
 
-        hdaR3StreamLock(pStream);
+        hdaR3StreamLock(pStreamR3);
 
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        hdaR3StreamAsyncIOLock(pStream);
+        hdaR3StreamAsyncIOLock(pStreamR3);
 # endif
         /* Make sure to remove the run bit before doing the actual stream reset. */
         HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_SDCTL_RUN;
 
-        hdaR3StreamReset(pThis, pStream, pStream->u8SD);
+        hdaR3StreamReset(pThis, pThisCC, pStreamShared, pStreamR3, uSD);
 
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        hdaR3StreamAsyncIOUnlock(pStream);
+        hdaR3StreamAsyncIOUnlock(pStreamR3);
 # endif
-        hdaR3StreamUnlock(pStream);
+        hdaR3StreamUnlock(pStreamR3);
     }
     else
@@ -1295,5 +1303,5 @@
             LogFunc(("[SD%RU8] State changed (fRun=%RTbool)\n", uSD, fRun));
 
-            hdaR3StreamLock(pStream);
+            hdaR3StreamLock(pStreamR3);
 
             int rc2 = VINF_SUCCESS;
@@ -1301,7 +1309,7 @@
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
             if (fRun)
-                rc2 = hdaR3StreamAsyncIOCreate(pStream);
-
-            hdaR3StreamAsyncIOLock(pStream);
+                rc2 = hdaR3StreamAsyncIOCreate(pStreamR3);
+
+            hdaR3StreamAsyncIOLock(pStreamR3);
 # endif
             if (fRun)
@@ -1316,22 +1324,19 @@
                 }
 
-                PHDATAG pTag = &pThis->aTags[uTag];
-                AssertPtr(pTag);
-
+                /* Assign new values. */
                 LogFunc(("[SD%RU8] Using stream tag=%RU8\n", uSD, uTag));
-
-                /* Assign new values. */
-                pTag->uTag    = uTag;
-                pTag->pStream = hdaGetStreamFromSD(pThis, uSD);
+                PHDATAG pTag = &pThisCC->aTags[uTag];
+                pTag->uTag      = uTag;
+                pTag->pStreamR3 = &pThisCC->aStreams[uSD];
 
 # ifdef LOG_ENABLED
                 PDMAUDIOPCMPROPS Props;
-                rc2 = hdaR3SDFMTToPCMProps(HDA_STREAM_REG(pThis, FMT, pStream->u8SD), &Props);
+                rc2 = hdaR3SDFMTToPCMProps(HDA_STREAM_REG(pThis, FMT, uSD), &Props);
                 AssertRC(rc2);
                 LogFunc(("[SD%RU8] %RU32Hz, %RU8bit, %RU8 channel(s)\n",
-                         pStream->u8SD, Props.uHz, Props.cbSample * 8 /* Bit */, Props.cChannels));
+                         uSD, Props.uHz, Props.cbSample * 8 /* Bit */, Props.cChannels));
 # endif
                 /* (Re-)initialize the stream with current values. */
-                rc2 = hdaR3StreamInit(pDevIns, pStream, pStream->u8SD);
+                rc2 = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, uSD);
                 if (   RT_SUCCESS(rc2)
                     /* Any vital stream change occurred so that we need to (re-)add the stream to our setup?
@@ -1340,9 +1345,9 @@
                 {
                     /* Remove the old stream from the device setup. */
-                    rc2 = hdaR3RemoveStream(pThis, &pStream->State.Cfg);
+                    rc2 = hdaR3RemoveStream(pThisCC, &pStreamShared->State.Cfg);
                     AssertRC(rc2);
 
                     /* Add the stream to the device setup. */
-                    rc2 = hdaR3AddStream(pThis, &pStream->State.Cfg);
+                    rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg);
                     AssertRC(rc2);
                 }
@@ -1352,5 +1357,5 @@
             {
                 /* Enable/disable the stream. */
-                rc2 = hdaR3StreamEnable(pStream, fRun /* fEnable */);
+                rc2 = hdaR3StreamEnable(pStreamShared, pStreamR3, fRun /* fEnable */);
                 AssertRC(rc2);
 
@@ -1358,16 +1363,17 @@
                 {
                     /* Keep track of running streams. */
-                    pThis->cStreamsActive++;
+                    pThisCC->cStreamsActive++;
 
                     /* (Re-)init the stream's period. */
-                    hdaR3StreamPeriodInit(&pStream->State.Period,
-                                          pStream->u8SD, pStream->u16LVI, pStream->u32CBL, &pStream->State.Cfg);
+                    hdaR3StreamPeriodInit(&pStreamShared->State.Period, uSD, pStreamShared->u16LVI,
+                                          pStreamShared->u32CBL, &pStreamShared->State.Cfg);
 
                     /* Begin a new period for this stream. */
-                    rc2 = hdaR3StreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */);
+                    rc2 = hdaR3StreamPeriodBegin(&pStreamShared->State.Period,
+                                                 hdaWalClkGetCurrent(pThis) /* Use current wall clock time */);
                     AssertRC(rc2);
 
-                    uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
-                    rc2 = hdaR3TimerSet(pDevIns, pStream, tsNow + pStream->State.cTransferTicks, false /* fForce */, tsNow);
+                    uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
+                    rc2 = hdaR3TimerSet(pDevIns, pStreamShared, tsNow + pStreamShared->State.cTransferTicks, false /* fForce */, tsNow);
                     AssertRC(rc2);
                 }
@@ -1375,26 +1381,26 @@
                 {
                     /* Keep track of running streams. */
-                    Assert(pThis->cStreamsActive);
-                    if (pThis->cStreamsActive)
-                        pThis->cStreamsActive--;
+                    Assert(pThisCC->cStreamsActive);
+                    if (pThisCC->cStreamsActive)
+                        pThisCC->cStreamsActive--;
 
                     /* Make sure to (re-)schedule outstanding (delayed) interrupts. */
-                    hdaR3ReschedulePendingInterrupts(pThis);
+                    hdaR3ReschedulePendingInterrupts(pDevIns, pThis, pThisCC);
 
                     /* Reset the period. */
-                    hdaR3StreamPeriodReset(&pStream->State.Period);
+                    hdaR3StreamPeriodReset(&pStreamShared->State.Period);
                 }
             }
 
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-            hdaR3StreamAsyncIOUnlock(pStream);
+            hdaR3StreamAsyncIOUnlock(pStreamR3);
 # endif
             /* Make sure to leave the lock before (eventually) starting the timer. */
-            hdaR3StreamUnlock(pStream);
+            hdaR3StreamUnlock(pStreamR3);
         }
     }
 
     if (fNeedVirtualSyncClockLock)
-        PDMDevHlpTimerUnlockClock(pDevIns, pStream->hTimer); /* Caller will unlock pThis->CritSect. */
+        PDMDevHlpTimerUnlockClock(pDevIns, pStreamShared->hTimer); /* Caller will unlock pThis->CritSect. */
 
     return hdaRegWriteU24(pDevIns, pThis, iReg, u32Value);
@@ -1409,19 +1415,20 @@
 #ifdef IN_RING3
     const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, STS, iReg);
-    PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
-    ASSERT_GUEST_LOGREL_MSG_RETURN(pStream, ("Guest tried writing SDSTS (0x%x) to unhandled stream #%RU8\n", u32Value, uSD),
-                                   VINF_SUCCESS);
+    AssertReturn(uSD < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
+    PHDASTATER3 const  pThisCC       = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    PHDASTREAMR3 const pStreamR3     = &pThisCC->aStreams[uSD];
+    PHDASTREAM const   pStreamShared = &pThis->aStreams[uSD];
 
     /* We only need to take the virtual-sync lock if we want to call
        PDMDevHlpTimerGet or hdaR3TimerSet later.  Only precondition for that
        is that we've got a non-zero ticks-per-transfer value. */
-    uint64_t const cTransferTicks = pStream->State.cTransferTicks;
+    uint64_t const cTransferTicks = pStreamShared->State.cTransferTicks;
     if (cTransferTicks)
     {
         DEVHDA_UNLOCK(pDevIns, pThis);
-        DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStream, VINF_IOM_R3_MMIO_WRITE);
-    }
-
-    hdaR3StreamLock(pStream);
+        DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStreamShared, VINF_IOM_R3_MMIO_WRITE);
+    }
+
+    hdaR3StreamLock(pStreamR3);
 
     uint32_t v = HDA_REG_IND(pThis, iReg);
@@ -1438,9 +1445,9 @@
     /* Some guests tend to write SDnSTS even if the stream is not running.
      * So make sure to check if the RUN bit is set first. */
-    const bool fRunning = pStream->State.fRunning;
-
-    Log3Func(("[SD%RU8] fRunning=%RTbool %R[sdsts]\n", pStream->u8SD, fRunning, v));
-
-    PHDASTREAMPERIOD pPeriod = &pStream->State.Period;
+    const bool fRunning = pStreamShared->State.fRunning;
+
+    Log3Func(("[SD%RU8] fRunning=%RTbool %R[sdsts]\n", uSD, fRunning, v));
+
+    PHDASTREAMPERIOD pPeriod = &pStreamShared->State.Period;
     hdaR3StreamPeriodLock(pPeriod);
     if (hdaR3StreamPeriodNeedsInterrupt(pPeriod))
@@ -1450,7 +1457,7 @@
         /* Make sure to try to update the WALCLK register if a period is complete.
          * Use the maximum WALCLK value all (active) streams agree to. */
-        const uint64_t uWalClkMax = hdaR3WalClkGetMax(pThis);
+        const uint64_t uWalClkMax = hdaR3WalClkGetMax(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));
         if (uWalClkMax > hdaWalClkGetCurrent(pThis))
-            hdaR3WalClkSet(pThis, uWalClkMax, false /* fForce */);
+            hdaR3WalClkSet(pThis, pThisCC, uWalClkMax, false /* fForce */);
 
         hdaR3StreamPeriodEnd(pPeriod);
@@ -1466,21 +1473,21 @@
      * ...
      */
-    uint64_t cTicksToNext = pStream->State.cTransferTicks;
+    uint64_t cTicksToNext = pStreamShared->State.cTransferTicks;
     Assert(cTicksToNext == cTicksToNext);
     if (cTicksToNext) /* Only do any calculations if the stream currently is set up for transfers. */
     {
-        const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
-        Assert(tsNow >= pStream->State.tsTransferLast);
-
-        const uint64_t cTicksElapsed     = tsNow - pStream->State.tsTransferLast;
+        const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
+        Assert(tsNow >= pStreamShared->State.tsTransferLast);
+
+        const uint64_t cTicksElapsed     = tsNow - pStreamShared->State.tsTransferLast;
 # ifdef LOG_ENABLED
-        const uint64_t cTicksTransferred = pStream->State.cbTransferProcessed * pStream->State.cTicksPerByte;
+        const uint64_t cTicksTransferred = pStreamShared->State.cbTransferProcessed * pStreamShared->State.cTicksPerByte;
 # endif
 
         Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksTransferred=%RU64, cTicksToNext=%RU64\n",
-                  pStream->u8SD, cTicksElapsed, cTicksTransferred, cTicksToNext));
-
-        Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n",
-                  pStream->u8SD, pStream->State.cbTransferProcessed, pStream->State.cbTransferChunk, pStream->State.cbTransferSize));
+                  uSD, cTicksElapsed, cTicksTransferred, cTicksToNext));
+
+        Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n", uSD,
+                  pStreamShared->State.cbTransferProcessed, pStreamShared->State.cbTransferChunk, pStreamShared->State.cbTransferSize));
 
         if (cTicksElapsed <= cTicksToNext)
@@ -1489,36 +1496,36 @@
         {
             Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",
-                     pStream->u8SD, cTicksElapsed, cTicksToNext));
-
-            LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n",
-                            pStream->u8SD,
-                            (PDMDevHlpTimerGetFreq(pDevIns, pStream->hTimer) / pThis->uTimerHz) / 1000,
-                            (tsNow - pStream->State.tsTransferLast) / 1000));
+                     uSD, cTicksElapsed, cTicksToNext));
+
+            LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n", uSD,
+                            (PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer) / pThis->uTimerHz) / 1000,
+                            (tsNow - pStreamShared->State.tsTransferLast) / 1000));
 
             cTicksToNext = 0;
         }
 
-        Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", pStream->u8SD, cTicksToNext));
+        Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", uSD, cTicksToNext));
 
         /* Reset processed data counter. */
-        pStream->State.cbTransferProcessed = 0;
-        pStream->State.tsTransferNext      = tsNow + cTicksToNext;
+        pStreamShared->State.cbTransferProcessed = 0;
+        pStreamShared->State.tsTransferNext      = tsNow + cTicksToNext;
 
         /* Only re-arm the timer if there were pending transfer interrupts left
          *  -- it could happen that we land in here if a guest writes to SDnSTS
          * unconditionally. */
-        if (pStream->State.cTransferPendingInterrupts)
-        {
-            pStream->State.cTransferPendingInterrupts--;
+        if (pStreamShared->State.cTransferPendingInterrupts)
+        {
+            pStreamShared->State.cTransferPendingInterrupts--;
 
             /* Re-arm the timer. */
-            LogFunc(("Timer set SD%RU8\n", pStream->u8SD));
-            hdaR3TimerSet(pDevIns, pStream, tsNow + cTicksToNext, true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);
+            LogFunc(("Timer set SD%RU8\n", uSD));
+            hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,
+                          true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);
         }
     }
 
     if (cTransferTicks)
-        PDMDevHlpTimerUnlockClock(pDevIns, pStream->hTimer); /* Caller will unlock pThis->CritSect. */
-    hdaR3StreamUnlock(pStream);
+        PDMDevHlpTimerUnlockClock(pDevIns, pStreamShared->hTimer); /* Caller will unlock pThis->CritSect. */
+    hdaR3StreamUnlock(pStreamR3);
     return VINF_SUCCESS;
 #else  /* !IN_RING3 */
@@ -1530,5 +1537,6 @@
 static VBOXSTRICTRC hdaRegWriteSDLVI(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
+    const size_t idxStream = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
+    AssertReturn(idxStream < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
 
 #ifdef HDA_USE_DMA_ACCESS_HANDLER
@@ -1537,5 +1545,5 @@
         /* Try registering the DMA handlers.
          * As we can't be sure in which order LVI + BDL base are set, try registering in both routines. */
-        PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
+        PHDASTREAM pStream = hdaGetStreamFromSD(pThis, idxStream);
         if (   pStream
             && hdaR3StreamRegisterDMAHandlers(pThis, pStream))
@@ -1545,5 +1553,5 @@
 
     ASSERT_GUEST_LOGREL_MSG(u32Value <= UINT8_MAX, /* Should be covered by the register write mask, but just to make sure. */
-                            ("LVI for stream #%RU8 must not be bigger than %RU8\n", uSD, UINT8_MAX - 1));
+                            ("LVI for stream #%zu must not be bigger than %RU8\n", idxStream, UINT8_MAX - 1));
     return hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
 }
@@ -1551,12 +1559,13 @@
 static VBOXSTRICTRC hdaRegWriteSDFIFOW(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg);
-
-    if (RT_LIKELY(hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN)) /* FIFOW for input streams only. */
+    size_t const idxStream = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg);
+    AssertReturn(idxStream < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
+
+    if (RT_LIKELY(hdaGetDirFromSD((uint8_t)idxStream) == PDMAUDIODIR_IN)) /* FIFOW for input streams only. */
     { /* likely */ }
     else
     {
 #ifndef IN_RING0
-        LogRel(("HDA: Warning: Guest tried to write read-only FIFOW to output stream #%RU8, ignoring\n", uSD));
+        LogRel(("HDA: Warning: Guest tried to write read-only FIFOW to output stream #%RU8, ignoring\n", idxStream));
         return VINF_SUCCESS;
 #else
@@ -1565,28 +1574,24 @@
     }
 
-    PHDASTREAM pStream = hdaGetStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg));
-    if (pStream)
-    {
-        uint32_t u32FIFOW = 0;
-        switch (u32Value)
-        {
-            case HDA_SDFIFOW_8B:
-            case HDA_SDFIFOW_16B:
-            case HDA_SDFIFOW_32B:
-                u32FIFOW = u32Value;
-                break;
-            default:
-                ASSERT_GUEST_LOGREL_MSG_FAILED(("Guest tried writing unsupported FIFOW (0x%x) to stream #%RU8, defaulting to 32 bytes\n",
-                                                u32Value, uSD));
-                u32FIFOW = HDA_SDFIFOW_32B;
-                break;
-        }
-
-        if (u32FIFOW) /** @todo r=bird: Logic error. it will never be zero, so why this check? */
-        {
-            pStream->u16FIFOW = hdaSDFIFOWToBytes(u32FIFOW);
-            LogFunc(("[SD%RU8] Updating FIFOW to %RU32 bytes\n", uSD, pStream->u16FIFOW));
-            return hdaRegWriteU16(pDevIns, pThis, iReg, u32FIFOW);
-        }
+    uint32_t u32FIFOW = 0;
+    switch (u32Value)
+    {
+        case HDA_SDFIFOW_8B:
+        case HDA_SDFIFOW_16B:
+        case HDA_SDFIFOW_32B:
+            u32FIFOW = u32Value;
+            break;
+        default:
+            ASSERT_GUEST_LOGREL_MSG_FAILED(("Guest tried writing unsupported FIFOW (0x%zx) to stream #%RU8, defaulting to 32 bytes\n",
+                                            u32Value, idxStream));
+            u32FIFOW = HDA_SDFIFOW_32B;
+            break;
+    }
+
+    if (u32FIFOW) /** @todo r=bird: Logic error. it will never be zero, so why this check? */
+    {
+        pThis->aStreams[idxStream].u16FIFOW = hdaSDFIFOWToBytes(u32FIFOW);
+        LogFunc(("[SD%zu] Updating FIFOW to %u bytes\n", idxStream, pThis->aStreams[idxStream].u16FIFOW));
+        return hdaRegWriteU16(pDevIns, pThis, iReg, u32FIFOW);
     }
     return VINF_SUCCESS;
@@ -1632,10 +1637,9 @@
  *
  * @returns IPRT status code.
- * @param   pThis               Device state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   pCfg                Stream configuration to use for adding a stream.
  */
-static int hdaR3AddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+static int hdaR3AddStreamOut(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
+{
     AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
 
@@ -1718,5 +1722,5 @@
             pCfg->Props.cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cbSample, pCfg->Props.cChannels);
 
-            rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT, pCfg);
+            rc = hdaCodecAddStream(pThisCC->pCodec, PDMAUDIOMIXERCTL_FRONT, pCfg);
         }
 
@@ -1733,5 +1737,5 @@
             pCfg->Props.cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cbSample, pCfg->Props.cChannels);
 
-            rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
+            rc = hdaCodecAddStream(pThisCC->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
         }
 
@@ -1747,5 +1751,5 @@
             pCfg->Props.cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cbSample, pCfg->Props.cChannels);
 
-            rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR, pCfg);
+            rc = hdaCodecAddStream(pThisCC->pCodec, PDMAUDIOMIXERCTL_REAR, pCfg);
         }
 # endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
@@ -1761,10 +1765,9 @@
  *
  * @returns IPRT status code.
- * @param   pThis               Device state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   pCfg                Stream configuration to use for adding a stream.
  */
-static int hdaR3AddStreamIn(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+static int hdaR3AddStreamIn(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
+{
     AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
 
@@ -1774,18 +1777,13 @@
 
     int rc;
-
     switch (pCfg->u.enmSrc)
     {
         case PDMAUDIORECSRC_LINE:
-        {
-            rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
+            rc = hdaCodecAddStream(pThisCC->pCodec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
             break;
-        }
 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
         case PDMAUDIORECSRC_MIC:
-        {
-            rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
+            rc = hdaCodecAddStream(pThisCC->pCodec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
             break;
-        }
 # endif
         default:
@@ -1802,24 +1800,22 @@
  *
  * @returns IPRT status code.
- * @param   pThis               Device state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   pCfg                Stream configuration to use for adding a stream.
  */
-static int hdaR3AddStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+static int hdaR3AddStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
+{
     AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
 
+    LogFlowFuncEnter();
+
     int rc;
-
-    LogFlowFuncEnter();
-
     switch (pCfg->enmDir)
     {
         case PDMAUDIODIR_OUT:
-            rc = hdaR3AddStreamOut(pThis, pCfg);
+            rc = hdaR3AddStreamOut(pThisCC, pCfg);
             break;
 
         case PDMAUDIODIR_IN:
-            rc = hdaR3AddStreamIn(pThis, pCfg);
+            rc = hdaR3AddStreamIn(pThisCC, pCfg);
             break;
 
@@ -1839,10 +1835,9 @@
  *
  * @returns IPRT status code.
- * @param   pThis               Device state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   pCfg                Stream configuration to use for removing a stream.
  */
-static int hdaR3RemoveStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+static int hdaR3RemoveStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
+{
     AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
 
@@ -1898,5 +1893,5 @@
         && enmMixerCtl != PDMAUDIOMIXERCTL_UNKNOWN)
     {
-        rc = hdaCodecRemoveStream(pThis->pCodec, enmMixerCtl);
+        rc = hdaCodecRemoveStream(pThisCC->pCodec, enmMixerCtl);
     }
 
@@ -1993,6 +1988,7 @@
         HDA_REG(pThis, IRS) = HDA_IRS_ICB;  /* busy */
 
-        uint64_t uResp = 0;
-        int rc2 = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(uCmd, 0 /* LUN */), &uResp);
+        PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+        uint64_t    uResp   = 0;
+        int rc2 = pThisCC->pCodec->pfnLookup(pThisCC->pCodec, HDA_CODEC_CMD(uCmd, 0 /* LUN */), &uResp);
         if (RT_FAILURE(rc2))
             LogFunc(("Codec lookup failed with rc2=%Rrc\n", rc2));
@@ -2028,12 +2024,5 @@
             /* Do a RIRB reset. */
             if (pThis->cbRirbBuf)
-            {
-#ifdef IN_RING3
-                Assert(pThis->pu64RirbBuf);
-                RT_BZERO(pThis->pu64RirbBuf, pThis->cbRirbBuf);
-#else
-                return VINF_IOM_R3_MMIO_WRITE;
-#endif
-            }
+                RT_ZERO(pThis->au64RirbBuf);
 
             LogRel2(("HDA: RIRB reset\n"));
@@ -2057,4 +2046,8 @@
     VBOXSTRICTRC rc = hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
     AssertRC(VBOXSTRICTRC_VAL(rc));
+
+    /** @todo r=bird: Shouldn't we make sure the HDASTATE::u16RespIntCnt is below
+     *        the new RINTCNT value?  Or alterantively, make the DMA look take
+     *        this into account instead...  I'll do the later for now. */
 
     LogFunc(("Response interrupt count is now %RU8\n", HDA_REG(pThis, RINTCNT) & 0xFF));
@@ -2116,5 +2109,6 @@
     HDA_REG(pThis, RIRBSTS) &= ~(v & u32Value);
 
-    return HDA_PROCESS_INTERRUPT(pDevIns, pThis);
+    HDA_PROCESS_INTERRUPT(pDevIns, pThis);
+    return VINF_SUCCESS;
 }
 
@@ -2123,11 +2117,10 @@
 /**
  * Retrieves a corresponding sink for a given mixer control.
- * Returns NULL if no sink is found.
  *
- * @return  PHDAMIXERSINK
- * @param   pThis               HDA state.
+ * @return  Pointer to the sink, NULL if no sink is found.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   enmMixerCtl         Mixer control to get the corresponding sink for.
  */
-static PHDAMIXERSINK hdaR3MixerControlToSink(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
+static PHDAMIXERSINK hdaR3MixerControlToSink(PHDASTATER3 pThisCC, PDMAUDIOMIXERCTL enmMixerCtl)
 {
     PHDAMIXERSINK pSink;
@@ -2138,25 +2131,25 @@
             /* Fall through is intentional. */
         case PDMAUDIOMIXERCTL_FRONT:
-            pSink = &pThis->SinkFront;
+            pSink = &pThisCC->SinkFront;
             break;
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
         case PDMAUDIOMIXERCTL_CENTER_LFE:
-            pSink = &pThis->SinkCenterLFE;
+            pSink = &pThisCC->SinkCenterLFE;
             break;
         case PDMAUDIOMIXERCTL_REAR:
-            pSink = &pThis->SinkRear;
+            pSink = &pThisCC->SinkRear;
             break;
 # endif
         case PDMAUDIOMIXERCTL_LINE_IN:
-            pSink = &pThis->SinkLineIn;
+            pSink = &pThisCC->SinkLineIn;
             break;
 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
         case PDMAUDIOMIXERCTL_MIC_IN:
-            pSink = &pThis->SinkMicIn;
+            pSink = &pThisCC->SinkMicIn;
             break;
 # endif
         default:
+            AssertMsgFailed(("Unhandled mixer control\n"));
             pSink = NULL;
-            AssertMsgFailed(("Unhandled mixer control\n"));
             break;
     }
@@ -2169,16 +2162,16 @@
  *
  * @return IPRT status code.
- * @param  pThis                HDA state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param  pDrv                 HDA driver to add.
  */
-static int hdaR3MixerAddDrv(PHDASTATE pThis, PHDADRIVER pDrv)
+static int hdaR3MixerAddDrv(PHDASTATER3 pThisCC, PHDADRIVER pDrv)
 {
     int rc = VINF_SUCCESS;
 
-    PHDASTREAM pStream = hdaR3GetStreamFromSink(pThis, &pThis->SinkLineIn);
+    PHDASTREAM pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkLineIn);
     if (   pStream
         && DrvAudioHlpStreamCfgIsValid(&pStream->State.Cfg))
     {
-        int rc2 = hdaR3MixerAddDrvStream(pThis, pThis->SinkLineIn.pMixSink, &pStream->State.Cfg, pDrv);
+        int rc2 = hdaR3MixerAddDrvStream(pThisCC->SinkLineIn.pMixSink, &pStream->State.Cfg, pDrv);
         if (RT_SUCCESS(rc))
             rc = rc2;
@@ -2186,9 +2179,9 @@
 
 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-    pStream = hdaR3GetStreamFromSink(pThis, &pThis->SinkMicIn);
+    pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkMicIn);
     if (   pStream
         && DrvAudioHlpStreamCfgIsValid(&pStream->State.Cfg))
     {
-        int rc2 = hdaR3MixerAddDrvStream(pThis, pThis->SinkMicIn.pMixSink, &pStream->State.Cfg, pDrv);
+        int rc2 = hdaR3MixerAddDrvStream(pThisCC->SinkMicIn.pMixSink, &pStream->State.Cfg, pDrv);
         if (RT_SUCCESS(rc))
             rc = rc2;
@@ -2196,9 +2189,9 @@
 # endif
 
-    pStream = hdaR3GetStreamFromSink(pThis, &pThis->SinkFront);
+    pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkFront);
     if (   pStream
         && DrvAudioHlpStreamCfgIsValid(&pStream->State.Cfg))
     {
-        int rc2 = hdaR3MixerAddDrvStream(pThis, pThis->SinkFront.pMixSink, &pStream->State.Cfg, pDrv);
+        int rc2 = hdaR3MixerAddDrvStream(pThisCC->SinkFront.pMixSink, &pStream->State.Cfg, pDrv);
         if (RT_SUCCESS(rc))
             rc = rc2;
@@ -2206,18 +2199,18 @@
 
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-    pStream = hdaR3GetStreamFromSink(pThis, &pThis->SinkCenterLFE);
+    pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkCenterLFE);
     if (   pStream
         && DrvAudioHlpStreamCfgIsValid(&pStream->State.Cfg))
     {
-        int rc2 = hdaR3MixerAddDrvStream(pThis, pThis->SinkCenterLFE.pMixSink, &pStream->State.Cfg, pDrv);
+        int rc2 = hdaR3MixerAddDrvStream(pThisCC->SinkCenterLFE.pMixSink, &pStream->State.Cfg, pDrv);
         if (RT_SUCCESS(rc))
             rc = rc2;
     }
 
-    pStream = hdaR3GetStreamFromSink(pThis, &pThis->SinkRear);
+    pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkRear);
     if (   pStream
         && DrvAudioHlpStreamCfgIsValid(&pStream->State.Cfg))
     {
-        int rc2 = hdaR3MixerAddDrvStream(pThis, pThis->SinkRear.pMixSink, &pStream->State.Cfg, pDrv);
+        int rc2 = hdaR3MixerAddDrvStream(pThisCC->SinkRear.pMixSink, &pStream->State.Cfg, pDrv);
         if (RT_SUCCESS(rc))
             rc = rc2;
@@ -2232,18 +2225,17 @@
  * associated streams.
  *
- * @param pThis                 HDA state.
- * @param pDrv                  HDA driver to remove.
- */
-static void hdaR3MixerRemoveDrv(PHDASTATE pThis, PHDADRIVER pDrv)
-{
-    AssertPtrReturnVoid(pThis);
+ * @param   pThisCC             The ring-3 HDA device state.
+ * @param   pDrv                HDA driver to remove.
+ */
+static void hdaR3MixerRemoveDrv(PHDASTATER3 pThisCC, PHDADRIVER pDrv)
+{
     AssertPtrReturnVoid(pDrv);
 
     if (pDrv->LineIn.pMixStrm)
     {
-        if (AudioMixerSinkGetRecordingSource(pThis->SinkLineIn.pMixSink) == pDrv->LineIn.pMixStrm)
-            AudioMixerSinkSetRecordingSource(pThis->SinkLineIn.pMixSink, NULL);
-
-        AudioMixerSinkRemoveStream(pThis->SinkLineIn.pMixSink, pDrv->LineIn.pMixStrm);
+        if (AudioMixerSinkGetRecordingSource(pThisCC->SinkLineIn.pMixSink) == pDrv->LineIn.pMixStrm)
+            AudioMixerSinkSetRecordingSource(pThisCC->SinkLineIn.pMixSink, NULL);
+
+        AudioMixerSinkRemoveStream(pThisCC->SinkLineIn.pMixSink, pDrv->LineIn.pMixStrm);
         AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm);
         pDrv->LineIn.pMixStrm = NULL;
@@ -2253,8 +2245,8 @@
     if (pDrv->MicIn.pMixStrm)
     {
-        if (AudioMixerSinkGetRecordingSource(pThis->SinkMicIn.pMixSink) == pDrv->MicIn.pMixStrm)
-            AudioMixerSinkSetRecordingSource(&pThis->SinkMicIn.pMixSink, NULL);
-
-        AudioMixerSinkRemoveStream(pThis->SinkMicIn.pMixSink, pDrv->MicIn.pMixStrm);
+        if (AudioMixerSinkGetRecordingSource(pThisCC->SinkMicIn.pMixSink) == pDrv->MicIn.pMixStrm)
+            AudioMixerSinkSetRecordingSource(&pThisCC->SinkMicIn.pMixSink, NULL);
+
+        AudioMixerSinkRemoveStream(pThisCC->SinkMicIn.pMixSink, pDrv->MicIn.pMixStrm);
         AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm);
         pDrv->MicIn.pMixStrm = NULL;
@@ -2264,5 +2256,5 @@
     if (pDrv->Front.pMixStrm)
     {
-        AudioMixerSinkRemoveStream(pThis->SinkFront.pMixSink, pDrv->Front.pMixStrm);
+        AudioMixerSinkRemoveStream(pThisCC->SinkFront.pMixSink, pDrv->Front.pMixStrm);
         AudioMixerStreamDestroy(pDrv->Front.pMixStrm);
         pDrv->Front.pMixStrm = NULL;
@@ -2272,5 +2264,5 @@
     if (pDrv->CenterLFE.pMixStrm)
     {
-        AudioMixerSinkRemoveStream(pThis->SinkCenterLFE.pMixSink, pDrv->CenterLFE.pMixStrm);
+        AudioMixerSinkRemoveStream(pThisCC->SinkCenterLFE.pMixSink, pDrv->CenterLFE.pMixStrm);
         AudioMixerStreamDestroy(pDrv->CenterLFE.pMixStrm);
         pDrv->CenterLFE.pMixStrm = NULL;
@@ -2279,5 +2271,5 @@
     if (pDrv->Rear.pMixStrm)
     {
-        AudioMixerSinkRemoveStream(pThis->SinkRear.pMixSink, pDrv->Rear.pMixStrm);
+        AudioMixerSinkRemoveStream(pThisCC->SinkRear.pMixSink, pDrv->Rear.pMixStrm);
         AudioMixerStreamDestroy(pDrv->Rear.pMixStrm);
         pDrv->Rear.pMixStrm = NULL;
@@ -2292,12 +2284,10 @@
  *
  * @returns IPRT status code (ignored by caller).
- * @param   pThis               HDA state.
  * @param   pMixSink            Audio mixer sink to add audio streams to.
  * @param   pCfg                Audio stream configuration to use for the audio streams to add.
  * @param   pDrv                Driver stream to add.
  */
-static int hdaR3MixerAddDrvStream(PHDASTATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg, PHDADRIVER pDrv)
-{
-    AssertPtrReturn(pThis,    VERR_INVALID_POINTER);
+static int hdaR3MixerAddDrvStream(PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg, PHDADRIVER pDrv)
+{
     AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
     AssertPtrReturn(pCfg,     VERR_INVALID_POINTER);
@@ -2417,11 +2407,10 @@
  *
  * @returns IPRT status code.
- * @param   pThis               HDA state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   pMixSink            Audio mixer sink to add stream to.
  * @param   pCfg                Audio stream configuration to use for the audio streams to add.
  */
-static int hdaR3MixerAddDrvStreams(PHDASTATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis,    VERR_INVALID_POINTER);
+static int hdaR3MixerAddDrvStreams(PHDASTATER3 pThisCC, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg)
+{
     AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
     AssertPtrReturn(pCfg,     VERR_INVALID_POINTER);
@@ -2437,7 +2426,7 @@
 
     PHDADRIVER pDrv;
-    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
-    {
-        int rc2 = hdaR3MixerAddDrvStream(pThis, pMixSink, pCfg, pDrv);
+    RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
+    {
+        int rc2 = hdaR3MixerAddDrvStream(pMixSink, pCfg, pDrv);
         if (RT_FAILURE(rc2))
             LogFunc(("Attaching stream failed with %Rrc\n", rc2));
@@ -2452,26 +2441,15 @@
 /**
  * @interface_method_impl{HDACODEC,pfnCbMixerAddStream}
- *
- * 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) hdaR3MixerAddStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ */
+static DECLCALLBACK(int) hdaR3MixerAddStream(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
+{
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
     AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
-
     int rc;
 
-    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThis, enmMixerCtl);
+    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
     if (pSink)
     {
-        rc = hdaR3MixerAddDrvStreams(pThis, pSink->pMixSink, pCfg);
+        rc = hdaR3MixerAddDrvStreams(pThisCC, pSink->pMixSink, pCfg);
 
         AssertPtr(pSink->pMixSink);
@@ -2487,24 +2465,15 @@
 /**
  * @interface_method_impl{HDACODEC,pfnCbMixerRemoveStream}
- *
- * Removes a specified mixer control from the HDA's mixer.
- *
- * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   enmMixerCtl         Mixer control to remove.
- *
- * @remarks Can be called as a callback by the HDA codec.
- */
-static DECLCALLBACK(int) hdaR3MixerRemoveStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
-{
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    int rc;
-
-    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThis, enmMixerCtl);
+ */
+static DECLCALLBACK(int) hdaR3MixerRemoveStream(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl)
+{
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    int         rc;
+
+    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
     if (pSink)
     {
         PHDADRIVER pDrv;
-        RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+        RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
         {
             PAUDMIXSTREAM pMixStream = NULL;
@@ -2568,17 +2537,10 @@
  * @interface_method_impl{HDACODEC,pfnCbMixerControl}
  *
- * Controls an input / output converter widget, that is, which converter is connected
- * to which stream (and channel).
- *
- * @returns IPRT status code.
- * @param   pThis               HDA State.
- * @param   enmMixerCtl         Mixer control to set SD stream number and channel for.
- * @param   uSD                 SD stream number (number + 1) to set. Set to 0 for unassign.
- * @param   uChannel            Channel to set. Only valid if a valid SD stream number is specified.
- *
- * @remarks Can be called as a callback by the HDA codec.
- */
-static DECLCALLBACK(int) hdaR3MixerControl(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
-{
+ * @note Is also called directly by the DevHDA code.
+ */
+static DECLCALLBACK(int) hdaR3MixerControl(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
+{
+    PHDASTATE   pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
     LogFunc(("enmMixerCtl=%s, uSD=%RU8, uChannel=%RU8\n", DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), uSD, uChannel));
 
@@ -2606,5 +2568,5 @@
     int rc = VINF_SUCCESS;
 
-    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThis, enmMixerCtl);
+    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
     if (pSink)
     {
@@ -2612,57 +2574,54 @@
 
         /* If this an output stream, determine the correct SD#. */
-        if (   (uSD < HDA_MAX_SDI)
+        if (   uSD < HDA_MAX_SDI
             && AudioMixerSinkGetDir(pSink->pMixSink) == AUDMIXSINKDIR_OUTPUT)
-        {
             uSD += HDA_MAX_SDI;
-        }
+
+        /* Make 100% sure we got a good stream number before continuing. */
+        AssertLogRelReturn(uSD < RT_ELEMENTS(pThisCC->aStreams), VERR_NOT_IMPLEMENTED);
 
         /* Detach the existing stream from the sink. */
-        if (   pSink->pStream
-            && (   pSink->pStream->u8SD      != uSD
-                || pSink->pStream->u8Channel != uChannel)
+        if (   pSink->pStreamShared
+            && pSink->pStreamR3
+            && (   pSink->pStreamShared->u8SD      != uSD
+                || pSink->pStreamShared->u8Channel != uChannel)
            )
         {
             LogFunc(("Sink '%s' was assigned to stream #%RU8 (channel %RU8) before\n",
-                     pSink->pMixSink->pszName, pSink->pStream->u8SD, pSink->pStream->u8Channel));
-
-            hdaR3StreamLock(pSink->pStream);
+                     pSink->pMixSink->pszName, pSink->pStreamShared->u8SD, pSink->pStreamShared->u8Channel));
+
+            hdaR3StreamLock(pSink->pStreamR3);
 
             /* Only disable the stream if the stream descriptor # has changed. */
-            if (pSink->pStream->u8SD != uSD)
-                hdaR3StreamEnable(pSink->pStream, false);
-
-            pSink->pStream->pMixSink = NULL;
-
-            hdaR3StreamUnlock(pSink->pStream);
-
-            pSink->pStream = NULL;
-        }
-
-        Assert(uSD < HDA_MAX_STREAMS);
+            if (pSink->pStreamShared->u8SD != uSD)
+                hdaR3StreamEnable(pSink->pStreamShared, pSink->pStreamR3, false /*fEnable*/);
+
+            pSink->pStreamR3->pMixSink = NULL;
+
+            hdaR3StreamUnlock(pSink->pStreamR3);
+
+            pSink->pStreamShared = NULL;
+            pSink->pStreamR3     = NULL;
+        }
 
         /* Attach the new stream to the sink.
          * Enabling the stream will be done by the gust via a separate SDnCTL call then. */
-        if (pSink->pStream == NULL)
+        if (pSink->pStreamShared == NULL)
         {
             LogRel2(("HDA: Setting sink '%s' to stream #%RU8 (channel %RU8), mixer control=%s\n",
                      pSink->pMixSink->pszName, uSD, uChannel, DrvAudioHlpAudMixerCtlToStr(enmMixerCtl)));
 
-            PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
-            if (pStream)
-            {
-                hdaR3StreamLock(pStream);
-
-                pSink->pStream = pStream;
-
-                pStream->u8Channel = uChannel;
-                pStream->pMixSink  = pSink;
-
-                hdaR3StreamUnlock(pStream);
-
-                rc = VINF_SUCCESS;
-            }
-            else
-                rc = VERR_NOT_IMPLEMENTED;
+            PHDASTREAMR3 pStreamR3     = &pThisCC->aStreams[uSD];
+            PHDASTREAM   pStreamShared = &pThis->aStreams[uSD];
+            hdaR3StreamLock(pStreamR3);
+
+            pSink->pStreamR3     = pStreamR3;
+            pSink->pStreamShared = pStreamShared;
+
+            pStreamShared->u8Channel = uChannel;
+            pStreamR3->pMixSink      = pSink;
+
+            hdaR3StreamUnlock(pStreamR3);
+            rc = VINF_SUCCESS;
         }
     }
@@ -2680,19 +2639,11 @@
 /**
  * @interface_method_impl{HDACODEC,pfnCbMixerSetVolume}
- *
- * 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.
- *
- * @remarks Can be called as a callback by the HDA codec.
- */
-static DECLCALLBACK(int) hdaR3MixerSetVolume(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol)
-{
-    int rc;
-
-    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThis, enmMixerCtl);
+ */
+static DECLCALLBACK(int) hdaR3MixerSetVolume(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol)
+{
+    PHDASTATER3   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    int           rc;
+
+    PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
     if (   pSink
         && pSink->pMixSink)
@@ -2717,27 +2668,30 @@
 static DECLCALLBACK(void) hdaR3Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
 {
-    PHDASTATE       pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
-    PHDASTREAM      pStream = (PHDASTREAM)pvUser;
-    TMTIMERHANDLE   hTimer  = pStream->hTimer;
+    PHDASTATE       pThis         = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3     pThisCC       = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    uintptr_t       idxStream     = (uintptr_t)pvUser;
+    AssertReturnVoid(idxStream < RT_ELEMENTS(pThis->aStreams));
+    PHDASTREAM      pStreamShared = &pThis->aStreams[idxStream];
+    PHDASTREAMR3    pStreamR3     = &pThisCC->aStreams[idxStream];
+    TMTIMERHANDLE   hTimer        = pStreamShared->hTimer;
     RT_NOREF(pTimer);
 
-    AssertPtr(pStream);
     Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
     Assert(PDMDevHlpTimerIsLockOwner(pDevIns, hTimer));
 
-    hdaR3StreamUpdate(pDevIns, pStream, true /* fInTimer */);
+    hdaR3StreamUpdate(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, true /* fInTimer */);
 
     /* Flag indicating whether to kick the timer again for a new data processing round. */
     bool fSinkActive = false;
-    if (pStream->pMixSink)
-        fSinkActive = AudioMixerSinkIsActive(pStream->pMixSink->pMixSink);
+    if (pStreamR3->pMixSink)
+        fSinkActive = AudioMixerSinkIsActive(pStreamR3->pMixSink->pMixSink);
 
     if (fSinkActive)
     {
         uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, hTimer); /* (For virtual sync this remains the same for the whole callout IIRC) */
-        const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStream, tsNow);
+        const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow);
         Log3Func(("fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", fSinkActive, fTimerScheduled));
         if (!fTimerScheduled)
-            hdaR3TimerSet(pDevIns, pStream, tsNow + PDMDevHlpTimerGetFreq(pDevIns, hTimer) / pThis->uTimerHz,
+            hdaR3TimerSet(pDevIns, pStreamShared, tsNow + PDMDevHlpTimerGetFreq(pDevIns, hTimer) / pThis->uTimerHz,
                           true /*fForce*/, tsNow /*fixed*/ );
     }
@@ -2882,12 +2836,13 @@
  * Soft reset of the device triggered via GCTL.
  *
- * @param   pThis   HDA state.
- *
- */
-static void hdaR3GCTLReset(PHDASTATE pThis)
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
+ */
+static void hdaR3GCTLReset(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
 {
     LogFlowFuncEnter();
 
-    pThis->cStreamsActive = 0;
+    pThisCC->cStreamsActive = 0;
 
     HDA_REG(pThis, GCAP)     = HDA_MAKE_GCAP(HDA_MAX_SDO, HDA_MAX_SDI, 0, 0, 1); /* see 6.2.1 */
@@ -2908,22 +2863,26 @@
      * Stop any audio currently playing and/or recording.
      */
-    pThis->SinkFront.pStream = NULL;
-    if (pThis->SinkFront.pMixSink)
-        AudioMixerSinkReset(pThis->SinkFront.pMixSink);
+    pThisCC->SinkFront.pStreamShared = NULL;
+    pThisCC->SinkFront.pStreamR3     = NULL;
+    if (pThisCC->SinkFront.pMixSink)
+        AudioMixerSinkReset(pThisCC->SinkFront.pMixSink);
 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-    pThis->SinkMicIn.pStream = NULL;
-    if (pThis->SinkMicIn.pMixSink)
-        AudioMixerSinkReset(pThis->SinkMicIn.pMixSink);
+    pThisCC->SinkMicIn.pStreamShared = NULL;
+    pThisCC->SinkMicIn.pStreamR3     = NULL;
+    if (pThisCC->SinkMicIn.pMixSink)
+        AudioMixerSinkReset(pThisCC->SinkMicIn.pMixSink);
 # endif
-    pThis->SinkLineIn.pStream = NULL;
-    if (pThis->SinkLineIn.pMixSink)
-        AudioMixerSinkReset(pThis->SinkLineIn.pMixSink);
+    pThisCC->SinkLineIn.pStreamShared = NULL;
+    pThisCC->SinkLineIn.pStreamR3     = NULL;
+    if (pThisCC->SinkLineIn.pMixSink)
+        AudioMixerSinkReset(pThisCC->SinkLineIn.pMixSink);
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-    pThis->SinkCenterLFE = NULL;
-    if (pThis->SinkCenterLFE.pMixSink)
-        AudioMixerSinkReset(pThis->SinkCenterLFE.pMixSink);
-    pThis->SinkRear.pStream = NULL;
-    if (pThis->SinkRear.pMixSink)
-        AudioMixerSinkReset(pThis->SinkRear.pMixSink);
+    pThisCC->SinkCenterLFE = NULL;
+    if (pThisCC->SinkCenterLFE.pMixSink)
+        AudioMixerSinkReset(pThisCC->SinkCenterLFE.pMixSink);
+    pThisCC->SinkRear.pStreamShared = NULL;
+    pThisCC->SinkRear.pStreamR3     = NULL;
+    if (pThisCC->SinkRear.pMixSink)
+        AudioMixerSinkReset(pThisCC->SinkRear.pMixSink);
 # endif
 
@@ -2931,8 +2890,8 @@
      * Reset the codec.
      */
-    if (   pThis->pCodec
-        && pThis->pCodec->pfnReset)
-    {
-        pThis->pCodec->pfnReset(pThis->pCodec);
+    if (   pThisCC->pCodec
+        && pThisCC->pCodec->pfnReset)
+    {
+        pThisCC->pCodec->pfnReset(pThisCC->pCodec);
     }
 
@@ -2944,39 +2903,41 @@
      * These stream numbers can be changed by the guest dynamically lateron.
      */
+    ASMCompilerBarrier(); /* paranoia */
 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-    hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_MIC_IN    , 1 /* SD0 */, 0 /* Channel */);
+    hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_MIC_IN    , 1 /* SD0 */, 0 /* Channel */);
 # endif
-    hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_LINE_IN   , 1 /* SD0 */, 0 /* Channel */);
-
-    hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_FRONT     , 5 /* SD4 */, 0 /* Channel */);
+    hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_LINE_IN   , 1 /* SD0 */, 0 /* Channel */);
+
+    hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_FRONT     , 5 /* SD4 */, 0 /* Channel */);
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-    hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
-    hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_REAR      , 5 /* SD4 */, 0 /* Channel */);
+    hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
+    hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_REAR      , 5 /* SD4 */, 0 /* Channel */);
 # endif
+    ASMCompilerBarrier(); /* paranoia */
 
     /* Reset CORB. */
     pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
-    RT_BZERO(pThis->pu32CorbBuf, pThis->cbCorbBuf);
+    RT_ZERO(pThis->au32CorbBuf);
 
     /* Reset RIRB. */
     pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
-    RT_BZERO(pThis->pu64RirbBuf, pThis->cbRirbBuf);
+    RT_ZERO(pThis->au64RirbBuf);
 
     /* Clear our internal response interrupt counter. */
     pThis->u16RespIntCnt = 0;
 
-    for (uint8_t uSD = 0; uSD < HDA_MAX_STREAMS; ++uSD)
-    {
-        int rc2 = hdaR3StreamEnable(&pThis->aStreams[uSD], false /* fEnable */);
+    for (size_t idxStream = 0; idxStream < RT_ELEMENTS(pThis->aStreams); idxStream++)
+    {
+        int rc2 = hdaR3StreamEnable(&pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream], false /* fEnable */);
         if (RT_SUCCESS(rc2))
         {
             /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
-            HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_SDCTL_RUN;
-            hdaR3StreamReset(pThis, &pThis->aStreams[uSD], uSD);
+            HDA_STREAM_REG(pThis, CTL, idxStream) &= ~HDA_SDCTL_RUN;
+            hdaR3StreamReset(pThis, pThisCC, &pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream], (uint8_t)idxStream);
         }
     }
 
     /* Clear stream tags <-> objects mapping table. */
-    RT_ZERO(pThis->aTags);
+    RT_ZERO(pThisCC->aTags);
 
     /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
@@ -3426,5 +3387,5 @@
 
 
-static int hdaR3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStream)
+static int hdaR3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
 {
     PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
@@ -3433,21 +3394,25 @@
 # endif
 
-    Log2Func(("[SD%RU8]\n", pStream->u8SD));
+    Log2Func(("[SD%RU8]\n", pStreamShared->u8SD));
 
     /* Save stream ID. */
-    int rc = pHlp->pfnSSMPutU8(pSSM, pStream->u8SD);
+    Assert(pStreamShared->u8SD < HDA_MAX_STREAMS);
+    int rc = pHlp->pfnSSMPutU8(pSSM, pStreamShared->u8SD);
     AssertRCReturn(rc, rc);
-    Assert(pStream->u8SD < HDA_MAX_STREAMS);
-
-    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStream->State, sizeof(HDASTREAMSTATE), 0 /*fFlags*/, g_aSSMStreamStateFields7, NULL);
+
+    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State, sizeof(pStreamShared->State),
+                                 0 /*fFlags*/, g_aSSMStreamStateFields7, NULL);
     AssertRCReturn(rc, rc);
 
-    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStream->State.BDLE.Desc, sizeof(HDABDLEDESC), 0 /*fFlags*/, g_aSSMBDLEDescFields7, NULL);
+    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.BDLE.Desc, sizeof(pStreamShared->State.BDLE.Desc),
+                                 0 /*fFlags*/, g_aSSMBDLEDescFields7, NULL);
     AssertRCReturn(rc, rc);
 
-    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStream->State.BDLE.State, sizeof(HDABDLESTATE), 0 /*fFlags*/, g_aSSMBDLEStateFields7, NULL);
+    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.BDLE.State, sizeof(pStreamShared->State.BDLE.State),
+                                 0 /*fFlags*/,  g_aSSMBDLEStateFields7, NULL);
     AssertRCReturn(rc, rc);
 
-    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStream->State.Period, sizeof(HDASTREAMPERIOD), 0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
+    rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),
+                                 0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
     AssertRCReturn(rc, rc);
 
@@ -3455,8 +3420,8 @@
     uint32_t cbCircBufUsed = 0;
 
-    if (pStream->State.pCircBuf)
-    {
-        cbCircBufSize = (uint32_t)RTCircBufSize(pStream->State.pCircBuf);
-        cbCircBufUsed = (uint32_t)RTCircBufUsed(pStream->State.pCircBuf);
+    if (pStreamR3->State.pCircBuf)
+    {
+        cbCircBufSize = (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf);
+        cbCircBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
     }
 
@@ -3476,8 +3441,8 @@
          * So get the current read offset and serialize the buffer data manually based on that.
          */
-        size_t const offBuf = RTCircBufOffsetRead(pStream->State.pCircBuf);
+        size_t const offBuf = RTCircBufOffsetRead(pStreamR3->State.pCircBuf);
         void  *pvBuf;
         size_t cbBuf;
-        RTCircBufAcquireReadBlock(pStream->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
+        RTCircBufAcquireReadBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
         Assert(cbBuf);
         if (cbBuf)
@@ -3491,13 +3456,12 @@
             }
         }
-        RTCircBufReleaseReadBlock(pStream->State.pCircBuf, 0 /* Don't advance read pointer -- see comment above */);
-    }
-
-    Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n",
-              pStream->u8SD,
-              HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), HDA_STREAM_REG(pThis, CBL, pStream->u8SD), HDA_STREAM_REG(pThis, LVI, pStream->u8SD)));
+        RTCircBufReleaseReadBlock(pStreamR3->State.pCircBuf, 0 /* Don't advance read pointer -- see comment above */);
+    }
+
+    Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", pStreamR3->u8SD, HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD),
+              HDA_STREAM_REG(pThis, CBL, pStreamShared->u8SD), HDA_STREAM_REG(pThis, LVI, pStreamShared->u8SD)));
 
 #ifdef LOG_ENABLED
-    hdaR3BDLEDumpAll(pThis, pStream->u64BDLBase, pStream->u16LVI + 1);
+    hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
 #endif
 
@@ -3510,9 +3474,10 @@
 static DECLCALLBACK(int) hdaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
-    PHDASTATE     pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
-    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
+    PHDASTATE     pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    PCPDMDEVHLPR3 pHlp    = pDevIns->pHlpR3;
 
     /* Save Codec nodes states. */
-    hdaCodecSaveState(pDevIns, pThis->pCodec, pSSM);
+    hdaCodecSaveState(pDevIns, pThisCC->pCodec, pSSM);
 
     /* Save MMIO registers. */
@@ -3530,5 +3495,5 @@
     for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
     {
-        int rc = hdaR3SaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
+        int rc = hdaR3SaveStream(pDevIns, pSSM, &pThis->aStreams[i], &pThisCC->aStreams[i]);
         AssertRCReturn(rc, rc);
     }
@@ -3541,52 +3506,52 @@
  *
  * @param   pDevIns             The device instance.
- * @param   pThis               Pointer to HDA state.
- */
-static int hdaR3LoadExecPost(PPDMDEVINS pDevIns, PHDASTATE pThis)
-{
-    int rc = VINF_SUCCESS;
+ * @param   pThis               Pointer to the shared HDA state.
+ * @param   pThisCC             Pointer to the ring-3 HDA state.
+ */
+static int hdaR3LoadExecPost(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
+{
+    int rc = VINF_SUCCESS; /** @todo r=bird: Really, what's the point of this? */
 
     /*
      * Enable all previously active streams.
      */
-    for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
-    {
-        PHDASTREAM pStream = hdaGetStreamFromSD(pThis, i);
-        if (pStream)
-        {
+    for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
+    {
+        PHDASTREAM pStreamShared = &pThis->aStreams[i];
+
+        bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_SDCTL_RUN);
+        if (fActive)
+        {
+            PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[i];
+
             int rc2;
-
-            bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_SDCTL_RUN);
-            if (fActive)
-            {
 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-                /* Make sure to also create the async I/O thread before actually enabling the stream. */
-                rc2 = hdaR3StreamAsyncIOCreate(pStream);
-                AssertRC(rc2);
-
-                /* ... and enabling it. */
-                hdaR3StreamAsyncIOEnable(pStream, true /* fEnable */);
+            /* Make sure to also create the async I/O thread before actually enabling the stream. */
+            rc2 = hdaR3StreamAsyncIOCreate(pStreamR3);
+            AssertRC(rc2);
+
+            /* ... and enabling it. */
+            hdaR3StreamAsyncIOEnable(pStreamR3, true /* fEnable */);
 #endif
-                /* Resume the stream's period. */
-                hdaR3StreamPeriodResume(&pStream->State.Period);
-
-                /* (Re-)enable the stream. */
-                rc2 = hdaR3StreamEnable(pStream, true /* fEnable */);
-                AssertRC(rc2);
-
-                /* Add the stream to the device setup. */
-                rc2 = hdaR3AddStream(pThis, &pStream->State.Cfg);
-                AssertRC(rc2);
+            /* Resume the stream's period. */
+            hdaR3StreamPeriodResume(&pStreamShared->State.Period);
+
+            /* (Re-)enable the stream. */
+            rc2 = hdaR3StreamEnable(pStreamShared, pStreamR3, true /* fEnable */);
+            AssertRC(rc2);
+
+            /* Add the stream to the device setup. */
+            rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg);
+            AssertRC(rc2);
 
 #ifdef HDA_USE_DMA_ACCESS_HANDLER
-                /* (Re-)install the DMA handler. */
-                hdaR3StreamRegisterDMAHandlers(pThis, pStream);
+            /* (Re-)install the DMA handler. */
+            hdaR3StreamRegisterDMAHandlers(pThis, pStreamShared);
 #endif
-                if (hdaR3StreamTransferIsScheduled(pStream, PDMDevHlpTimerGet(pDevIns, pStream->hTimer)))
-                    hdaR3TimerSet(pDevIns, pStream, hdaR3StreamTransferGetNext(pStream), true /*fForce*/, 0 /*tsNow*/);
-
-                /* Also keep track of the currently active streams. */
-                pThis->cStreamsActive++;
-            }
+            if (hdaR3StreamTransferIsScheduled(pStreamShared, PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer)))
+                hdaR3TimerSet(pDevIns, pStreamShared, hdaR3StreamTransferGetNext(pStreamShared), true /*fForce*/, 0 /*tsNow*/);
+
+            /* Also keep track of the currently active streams. */
+            pThisCC->cStreamsActive++;
         }
     }
@@ -3601,9 +3566,10 @@
  *
  * @param   pDevIns     The device instance.
- * @param   pThis       Pointer to HDA state.
+ * @param   pThis       Pointer to the shared HDA state.
+ * @param   pThisCC     Pointer to the ring-3 HDA state.
  * @param   pSSM        Pointer to SSM handle.
  * @param   uVersion    Saved state version to load.
  */
-static int hdaR3LoadExecLegacy(PPDMDEVINS pDevIns, PHDASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion)
+static int hdaR3LoadExecLegacy(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PSSMHANDLE pSSM, uint32_t uVersion)
 {
     PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
@@ -3694,29 +3660,29 @@
 
             /* Output */
-            PHDASTREAM pStream = &pThis->aStreams[4];
-            rc = hdaR3StreamInit(pDevIns, pStream, 4 /* Stream descriptor, hardcoded */);
+            PHDASTREAM pStreamShared = &pThis->aStreams[4];
+            rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[4], 4 /* Stream descriptor, hardcoded */);
             AssertRCReturn(rc, rc);
-            rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE, sizeof(pStream->State.BDLE),
+            rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE, sizeof(pStreamShared->State.BDLE),
                                          0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
             AssertRCReturn(rc, rc);
-            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+            pStreamShared->State.uCurBDLE = pStreamShared->State.BDLE.State.u32BDLIndex;
 
             /* Microphone-In */
-            pStream = &pThis->aStreams[2];
-            rc = hdaR3StreamInit(pDevIns, pStream, 2 /* Stream descriptor, hardcoded */);
+            pStreamShared = &pThis->aStreams[2];
+            rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[2], 2 /* Stream descriptor, hardcoded */);
             AssertRCReturn(rc, rc);
-            rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE, sizeof(pStream->State.BDLE),
+            rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE, sizeof(pStreamShared->State.BDLE),
                                          0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
             AssertRCReturn(rc, rc);
-            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+            pStreamShared->State.uCurBDLE = pStreamShared->State.BDLE.State.u32BDLIndex;
 
             /* Line-In */
-            pStream = &pThis->aStreams[0];
-            rc = hdaR3StreamInit(pDevIns, pStream, 0 /* Stream descriptor, hardcoded */);
+            pStreamShared = &pThis->aStreams[0];
+            rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[0], 0 /* Stream descriptor, hardcoded */);
             AssertRCReturn(rc, rc);
-            rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE, sizeof(pStream->State.BDLE),
+            rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE, sizeof(pStreamShared->State.BDLE),
                                          0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
             AssertRCReturn(rc, rc);
-            pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+            pStreamShared->State.uCurBDLE = pStreamShared->State.BDLE.State.u32BDLIndex;
             break;
         }
@@ -3743,16 +3709,16 @@
                 AssertRCReturn(rc, rc);
 
-                HDASTREAM  StreamDummy;
-                PHDASTREAM pStream = hdaGetStreamFromSD(pThis, idStream);
-                if (!pStream)
-                {
-                    pStream = &StreamDummy;
-                    LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping loading it ...\n", idStream));
-                }
-
-                rc = hdaR3StreamInit(pDevIns, pStream, idStream);
+                HDASTREAM    StreamDummyShared;
+                HDASTREAMR3  StreamDummyR3;
+                PHDASTREAM   pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
+                PHDASTREAMR3 pStreamR3     = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
+                AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
+                                    ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
+                                    RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
+
+                rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
                 if (RT_FAILURE(rc))
                 {
-                    LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, idStream, rc));
+                    LogRel(("HDA: Stream #%RU32: Setting up of stream %RU8 failed, rc=%Rrc\n", i, idStream, rc));
                     break;
                 }
@@ -3779,5 +3745,5 @@
                     rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State1Fields, NULL);
                     AssertRCReturn(rc, rc);
-                    pStream->State.uCurBDLE = Tmp.uCurBDLE;
+                    pStreamShared->State.uCurBDLE = Tmp.uCurBDLE;
 
                     for (uint16_t a = 0; a < Tmp.cBLDEs; a++)
@@ -3792,8 +3758,8 @@
                         rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State2Fields, NULL);
                         AssertRCReturn(rc, rc);
-                        if (Tmp.u32BDLEIndex == pStream->State.uCurBDLE)
+                        if (Tmp.u32BDLEIndex == pStreamShared->State.uCurBDLE)
                         {
-                            pStream->State.BDLE.State.cbBelowFIFOW = Tmp.cbBelowFIFOW;
-                            pStream->State.BDLE.State.u32BufOff    = Tmp.u32BufOff;
+                            pStreamShared->State.BDLE.State.cbBelowFIFOW = Tmp.cbBelowFIFOW;
+                            pStreamShared->State.BDLE.State.u32BufOff    = Tmp.u32BufOff;
                         }
                     }
@@ -3801,13 +3767,13 @@
                 else
                 {
-                    rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State, sizeof(HDASTREAMSTATE),
+                    rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
                                                  0 /* fFlags */, g_aSSMStreamStateFields6, NULL);
                     AssertRCReturn(rc, rc);
 
-                    rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE.Desc, sizeof(pStream->State.BDLE.Desc),
+                    rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.Desc, sizeof(pStreamShared->State.BDLE.Desc),
                                                  0 /* fFlags */, g_aSSMBDLEDescFields6, pDevIns);
                     AssertRCReturn(rc, rc);
 
-                    rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE.State, sizeof(HDABDLESTATE),
+                    rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.State, sizeof(HDABDLESTATE),
                                                  0 /* fFlags */, g_aSSMBDLEStateFields6, NULL);
                     AssertRCReturn(rc, rc);
@@ -3816,5 +3782,5 @@
                               HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
 #ifdef LOG_ENABLED
-                    hdaR3BDLEDumpAll(pThis, pStream->u64BDLBase, pStream->u16LVI + 1);
+                    hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
 #endif
                 }
@@ -3833,6 +3799,7 @@
 static DECLCALLBACK(int) hdaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
 {
-    PHDASTATE     pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
-    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
+    PHDASTATE     pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+    PCPDMDEVHLPR3 pHlp    = pDevIns->pHlpR3;
 
     Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
@@ -3843,5 +3810,5 @@
      * Load Codec nodes states.
      */
-    int rc = hdaCodecLoadState(pDevIns, pThis->pCodec, pSSM, uVersion);
+    int rc = hdaCodecLoadState(pDevIns, pThisCC->pCodec, pSSM, uVersion);
     if (RT_FAILURE(rc))
     {
@@ -3852,7 +3819,7 @@
     if (uVersion <= HDA_SAVED_STATE_VERSION_6) /* Handle older saved states? */
     {
-        rc = hdaR3LoadExecLegacy(pDevIns, pThis, pSSM, uVersion);
+        rc = hdaR3LoadExecLegacy(pDevIns, pThis, pThisCC, pSSM, uVersion);
         if (RT_SUCCESS(rc))
-            rc = hdaR3LoadExecPost(pDevIns, pThis);
+            rc = hdaR3LoadExecPost(pDevIns, pThis, pThisCC);
         return rc;
     }
@@ -3918,22 +3885,20 @@
         AssertRCReturn(rc, rc);
 
-        PHDASTREAM pStream = hdaGetStreamFromSD(pThis, idStream);
-        HDASTREAM  StreamDummy;
-
-        if (!pStream)
-        {
-            RT_ZERO(StreamDummy);
-            pStream = &StreamDummy;
-            LogRel2(("HDA: Warning: Loading of stream #%RU8 not supported, skipping to load ...\n", idStream));
-        }
-
-        rc = hdaR3StreamInit(pDevIns, pStream, idStream);
+        HDASTREAM    StreamDummyShared;
+        HDASTREAMR3  StreamDummyR3;
+        PHDASTREAM   pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
+        PHDASTREAMR3 pStreamR3     = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
+        AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
+                            ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
+                            RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
+
+        rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
         if (RT_FAILURE(rc))
         {
-            LogRel(("HDA: Stream #%RU8: Loading initialization failed, rc=%Rrc\n", idStream, rc));
+            LogRel(("HDA: Stream #%RU8: Setting up failed, rc=%Rrc\n", idStream, rc));
             /* Continue. */
         }
 
-        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State, sizeof(HDASTREAMSTATE),
+        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
                                      0 /* fFlags */, g_aSSMStreamStateFields7, NULL);
         AssertRCReturn(rc, rc);
@@ -3942,20 +3907,21 @@
          * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
          */
-        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE.Desc, sizeof(HDABDLEDESC),
+        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.Desc, sizeof(HDABDLEDESC),
                                      0 /* fFlags */, g_aSSMBDLEDescFields7, NULL);
         AssertRCReturn(rc, rc);
 
-        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.BDLE.State, sizeof(HDABDLESTATE),
+        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.State, sizeof(HDABDLESTATE),
                                      0 /* fFlags */, g_aSSMBDLEStateFields7, NULL);
         AssertRCReturn(rc, rc);
 
-        Log2Func(("[SD%RU8] %R[bdle]\n", pStream->u8SD, &pStream->State.BDLE));
+        Log2Func(("[SD%RU8] %R[bdle]\n", pStreamShared->u8SD, &pStreamShared->State.BDLE));
 
         /*
          * Load period state.
          */
-        hdaR3StreamPeriodInit(&pStream->State.Period, pStream->u8SD, pStream->u16LVI, pStream->u32CBL, &pStream->State.Cfg);
-
-        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStream->State.Period, sizeof(HDASTREAMPERIOD),
+        hdaR3StreamPeriodInit(&pStreamShared->State.Period, pStreamShared->u8SD, pStreamShared->u16LVI,
+                              pStreamShared->u32CBL, &pStreamShared->State.Cfg);
+
+        rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),
                                      0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
         AssertRCReturn(rc, rc);
@@ -3983,12 +3949,12 @@
 
             /* Do we need to cre-create the circular buffer do fit the data size? */
-            if (   pStream->State.pCircBuf
-                && cbCircBufSize != (uint32_t)RTCircBufSize(pStream->State.pCircBuf))
+            if (   pStreamR3->State.pCircBuf
+                && cbCircBufSize != (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf))
             {
-                RTCircBufDestroy(pStream->State.pCircBuf);
-                pStream->State.pCircBuf = NULL;
+                RTCircBufDestroy(pStreamR3->State.pCircBuf);
+                pStreamR3->State.pCircBuf = NULL;
             }
 
-            rc = RTCircBufCreate(&pStream->State.pCircBuf, cbCircBufSize);
+            rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBufSize);
             AssertRCReturn(rc, rc);
 
@@ -3997,5 +3963,5 @@
                 void  *pvBuf;
                 size_t cbBuf;
-                RTCircBufAcquireWriteBlock(pStream->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
+                RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
 
                 AssertLogRelMsgReturn(cbBuf == cbCircBufUsed, ("cbBuf=%zu cbCircBufUsed=%zu\n", cbBuf, cbCircBufUsed),
@@ -4004,5 +3970,5 @@
                 AssertRCReturn(rc, rc);
 
-                RTCircBufReleaseWriteBlock(pStream->State.pCircBuf, cbBuf);
+                RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbBuf);
 
                 Assert(cbBuf == cbCircBufUsed);
@@ -4013,5 +3979,5 @@
                   HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
 #ifdef LOG_ENABLED
-        hdaR3BDLEDumpAll(pThis, pStream->u64BDLBase, pStream->u16LVI + 1);
+        hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
 #endif
         /** @todo (Re-)initialize active periods? */
@@ -4019,5 +3985,5 @@
     } /* for cStreams */
 
-    rc = hdaR3LoadExecPost(pDevIns, pThis);
+    rc = hdaR3LoadExecPost(pDevIns, pThis, pThisCC);
     AssertRC(rc);
 
@@ -4170,5 +4136,5 @@
 }
 
-static void hdaR3DbgPrintBDLE(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
+static void hdaR3DbgPrintBDLE(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
 {
     Assert(   pThis
@@ -4197,5 +4163,5 @@
     {
         HDABDLEDESC bd;
-        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
+        PDMDevHlpPhysRead(pDevIns, u64BaseDMA + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
 
         pHlp->pfnPrintf(pHlp, "\t\t%s #%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n",
@@ -4220,5 +4186,5 @@
     {
         uint32_t uDMACnt;
-        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
+        PDMDevHlpPhysRead(pDevIns, (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
                           &uDMACnt, sizeof(uDMACnt));
 
@@ -4256,8 +4222,8 @@
     int         iHdaStreamdex = hdaR3DbgLookupStrmIdx(pThis, pszArgs);
     if (iHdaStreamdex != -1)
-        hdaR3DbgPrintBDLE(pThis, pHlp, iHdaStreamdex);
+        hdaR3DbgPrintBDLE(pDevIns, pThis, pHlp, iHdaStreamdex);
     else
         for (iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
-            hdaR3DbgPrintBDLE(pThis, pHlp, iHdaStreamdex);
+            hdaR3DbgPrintBDLE(pDevIns, pThis, pHlp, iHdaStreamdex);
 }
 
@@ -4267,8 +4233,8 @@
 static DECLCALLBACK(void) hdaR3DbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
-
-    if (pThis->pCodec->pfnDbgListNodes)
-        pThis->pCodec->pfnDbgListNodes(pThis->pCodec, pHlp, pszArgs);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+
+    if (pThisCC->pCodec->pfnDbgListNodes)
+        pThisCC->pCodec->pfnDbgListNodes(pThisCC->pCodec, pHlp, pszArgs);
     else
         pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
@@ -4280,8 +4246,8 @@
 static DECLCALLBACK(void) hdaR3DbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
-
-    if (pThis->pCodec->pfnDbgSelector)
-        pThis->pCodec->pfnDbgSelector(pThis->pCodec, pHlp, pszArgs);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+
+    if (pThisCC->pCodec->pfnDbgSelector)
+        pThisCC->pCodec->pfnDbgSelector(pThisCC->pCodec, pHlp, pszArgs);
     else
         pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
@@ -4293,8 +4259,8 @@
 static DECLCALLBACK(void) hdaR3DbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
-
-    if (pThis->pMixer)
-        AudioMixerDebug(pThis->pMixer, pHlp, pszArgs);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
+
+    if (pThisCC->pMixer)
+        AudioMixerDebug(pThisCC->pMixer, pHlp, pszArgs);
     else
         pHlp->pfnPrintf(pHlp, "Mixer not available\n");
@@ -4311,8 +4277,7 @@
 static DECLCALLBACK(void *) hdaR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
 {
-    PHDASTATE pThis = RT_FROM_MEMBER(pInterface, HDASTATE, IBase);
-    Assert(&pThis->IBase == pInterface);
-
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
+    PHDASTATER3 pThisCC = RT_FROM_MEMBER(pInterface, HDASTATER3, IBase);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
     return NULL;
 }
@@ -4331,10 +4296,12 @@
  *
  * @returns VBox status code.
- * @param   pThis       HDA state.
+ * @param   pDevIns     The device instance.
+ * @param   pThis       The shared HDA device state.
+ * @param   pThisR3     The ring-3 HDA device state.
  * @param   uLUN        The logical unit which is being detached.
  * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
  * @param   ppDrv       Attached driver instance on success. Optional.
  */
-static int hdaR3AttachInternal(PHDASTATE pThis, unsigned uLUN, uint32_t fFlags, PHDADRIVER *ppDrv)
+static int hdaR3AttachInternal(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned uLUN, uint32_t fFlags, PHDADRIVER *ppDrv)
 {
     RT_NOREF(fFlags);
@@ -4348,6 +4315,5 @@
 
     PPDMIBASE pDrvBase;
-    int rc = PDMDevHlpDriverAttach(pThis->pDevInsR3, uLUN,
-                                   &pThis->IBase, &pDrvBase, pszDesc);
+    int rc = PDMDevHlpDriverAttach(pDevIns, uLUN, &pThisCC->IBase, &pDrvBase, pszDesc);
     if (RT_SUCCESS(rc))
     {
@@ -4355,9 +4321,10 @@
         if (pDrv)
         {
-            pDrv->pDrvBase   = pDrvBase;
-            pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
+            pDrv->pDrvBase          = pDrvBase;
+            pDrv->pHDAStateShared   = pThis;
+            pDrv->pHDAStateR3       = pThisCC;
+            pDrv->uLUN              = uLUN;
+            pDrv->pConnector        = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
             AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN#%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
-            pDrv->pHDAState  = pThis;
-            pDrv->uLUN       = uLUN;
 
             /*
@@ -4373,5 +4340,5 @@
             if (!pDrv->fAttached)
             {
-                RTListAppend(&pThis->lstDrv, &pDrv->Node);
+                RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
                 pDrv->fAttached = true;
             }
@@ -4404,9 +4371,9 @@
  *
  * @returns VBox status code.
- * @param   pThis       HDA state.
+ * @param   pThisR3     The ring-3 HDA device state.
  * @param   pDrv        Driver to detach from device.
  * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
  */
-static int hdaR3DetachInternal(PHDASTATE pThis, PHDADRIVER pDrv, uint32_t fFlags)
+static int hdaR3DetachInternal(PHDASTATER3 pThisCC, PHDADRIVER pDrv, uint32_t fFlags)
 {
     RT_NOREF(fFlags);
@@ -4414,10 +4381,10 @@
     /* First, remove the driver from our list and destory it's associated streams.
      * This also will un-set the driver as a recording source (if associated). */
-    hdaR3MixerRemoveDrv(pThis, pDrv);
+    hdaR3MixerRemoveDrv(pThisCC, pDrv);
 
     /* Next, search backwards for a capable (attached) driver which now will be the
      * new recording source. */
     PHDADRIVER pDrvCur;
-    RTListForEachReverse(&pThis->lstDrv, pDrvCur, HDADRIVER, Node)
+    RTListForEachReverse(&pThisCC->lstDrv, pDrvCur, HDADRIVER, Node)
     {
         if (!pDrvCur->pConnector)
@@ -4435,5 +4402,5 @@
             && pDrvStrm->pMixStrm)
         {
-            rc2 = AudioMixerSinkSetRecordingSource(pThis->SinkMicIn.pMixSink, pDrvStrm->pMixStrm);
+            rc2 = AudioMixerSinkSetRecordingSource(pThisCC->SinkMicIn.pMixSink, pDrvStrm->pMixStrm);
             if (RT_SUCCESS(rc2))
                 LogRel2(("HDA: Set new recording source for 'Mic In' to '%s'\n", Cfg.szName));
@@ -4444,5 +4411,5 @@
             && pDrvStrm->pMixStrm)
         {
-            rc2 = AudioMixerSinkSetRecordingSource(pThis->SinkLineIn.pMixSink, pDrvStrm->pMixStrm);
+            rc2 = AudioMixerSinkSetRecordingSource(pThisCC->SinkLineIn.pMixSink, pDrvStrm->pMixStrm);
             if (RT_SUCCESS(rc2))
                 LogRel2(("HDA: Set new recording source for 'Line In' to '%s'\n", Cfg.szName));
@@ -4459,5 +4426,6 @@
 static DECLCALLBACK(int) hdaR3Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATE   pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
 
     DEVHDA_LOCK_RETURN(pDevIns, pThis, VERR_IGNORED);
@@ -4466,7 +4434,7 @@
 
     PHDADRIVER pDrv;
-    int rc2 = hdaR3AttachInternal(pThis, uLUN, fFlags, &pDrv);
+    int rc2 = hdaR3AttachInternal(pDevIns, pThis, pThisCC, uLUN, fFlags, &pDrv);
     if (RT_SUCCESS(rc2))
-        rc2 = hdaR3MixerAddDrv(pThis, pDrv);
+        rc2 = hdaR3MixerAddDrv(pThisCC, pDrv);
 
     if (RT_FAILURE(rc2))
@@ -4483,5 +4451,6 @@
 static DECLCALLBACK(void) hdaR3Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATE   pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
 
     DEVHDA_LOCK(pDevIns, pThis);
@@ -4490,9 +4459,9 @@
 
     PHDADRIVER pDrv, pDrvNext;
-    RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, HDADRIVER, Node)
+    RTListForEachSafe(&pThisCC->lstDrv, pDrv, pDrvNext, HDADRIVER, Node)
     {
         if (pDrv->uLUN == uLUN)
         {
-            int rc2 = hdaR3DetachInternal(pThis, pDrv, fFlags);
+            int rc2 = hdaR3DetachInternal(pThisCC, pDrv, fFlags);
             if (RT_SUCCESS(rc2))
             {
@@ -4515,5 +4484,6 @@
 static DECLCALLBACK(void) hdaR3PowerOff(PPDMDEVINS pDevIns)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATE   pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
 
     DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
@@ -4522,5 +4492,5 @@
 
     /* Ditto goes for the codec, which in turn uses the mixer. */
-    hdaCodecPowerOff(pThis->pCodec);
+    hdaCodecPowerOff(pThisCC->pCodec);
 
     /*
@@ -4529,8 +4499,8 @@
      *       PDM audio streams it maintains.
      */
-    if (pThis->pMixer)
-    {
-        AudioMixerDestroy(pThis->pMixer);
-        pThis->pMixer = NULL;
+    if (pThisCC->pMixer)
+    {
+        AudioMixerDestroy(pThisCC->pMixer);
+        pThisCC->pMixer = NULL;
     }
 
@@ -4542,12 +4512,15 @@
  *
  * @returns VBox status code.
+ * @param   pDevIns     The device instance.
+ * @param   pThis       The shared HDA device state.
+ * @param   pThisCC     The ring-3 HDA device state.
  * @param   pThis       Device instance.
  * @param   iLun        The logical unit which is being replaced.
  */
-static int hdaR3ReconfigLunWithNullAudio(PHDASTATE pThis, unsigned iLun)
-{
-    int rc = PDMDevHlpDriverReconfigure2(pThis->pDevInsR3, iLun, "AUDIO", "NullAudio");
+static int hdaR3ReconfigLunWithNullAudio(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned iLun)
+{
+    int rc = PDMDevHlpDriverReconfigure2(pDevIns, iLun, "AUDIO", "NullAudio");
     if (RT_SUCCESS(rc))
-        rc = hdaR3AttachInternal(pThis, iLun, 0 /* fFlags */, NULL /* ppDrv */);
+        rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, 0 /* fFlags */, NULL /* ppDrv */);
     LogFunc(("pThis=%p, iLun=%u, rc=%Rrc\n", pThis, iLun, rc));
     return rc;
@@ -4560,5 +4533,6 @@
 static DECLCALLBACK(void) hdaR3Reset(PPDMDEVINS pDevIns)
 {
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATE   pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
 
     LogFlowFuncEnter();
@@ -4572,5 +4546,5 @@
     HDA_REG(pThis, WAKEEN)  = 0x0;
 
-    hdaR3GCTLReset(pThis);
+    hdaR3GCTLReset(pDevIns, pThis, pThisCC);
 
     /* Indicate that HDA is not in reset. The firmware is supposed to (un)reset HDA,
@@ -4589,11 +4563,12 @@
 {
     PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
-    PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATE   pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
     DEVHDA_LOCK(pDevIns, pThis); /** @todo r=bird: this will fail on early constructor failure. */
 
     PHDADRIVER pDrv;
-    while (!RTListIsEmpty(&pThis->lstDrv))
-    {
-        pDrv = RTListGetFirst(&pThis->lstDrv, HDADRIVER, Node);
+    while (!RTListIsEmpty(&pThisCC->lstDrv))
+    {
+        pDrv = RTListGetFirst(&pThisCC->lstDrv, HDADRIVER, Node);
 
         RTListNodeRemove(&pDrv->Node);
@@ -4601,20 +4576,14 @@
     }
 
-    if (pThis->pCodec)
-    {
-        hdaCodecDestruct(pThis->pCodec);
-
-        RTMemFree(pThis->pCodec);
-        pThis->pCodec = NULL;
-    }
-
-    RTMemFree(pThis->pu32CorbBuf);
-    pThis->pu32CorbBuf = NULL;
-
-    RTMemFree(pThis->pu64RirbBuf);
-    pThis->pu64RirbBuf = NULL;
+    if (pThisCC->pCodec)
+    {
+        hdaCodecDestruct(pThisCC->pCodec);
+
+        RTMemFree(pThisCC->pCodec);
+        pThisCC->pCodec = NULL;
+    }
 
     for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
-        hdaR3StreamDestroy(&pThis->aStreams[i]);
+        hdaR3StreamDestroy(&pThis->aStreams[i], &pThisCC->aStreams[i]);
 
     DEVHDA_UNLOCK(pDevIns, pThis);
@@ -4630,4 +4599,5 @@
     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
     PHDASTATE       pThis   = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
+    PHDASTATER3     pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
     PCPDMDEVHLPR3   pHlp    = pDevIns->pHlpR3;
     Assert(iInstance == 0); RT_NOREF(iInstance);
@@ -4637,5 +4607,8 @@
      */
     pThis->uAlignmentCheckMagic = HDASTATE_ALIGNMENT_CHECK_MAGIC;
-    RTListInit(&pThis->lstDrv);
+    RTListInit(&pThisCC->lstDrv);
+    pThis->cbCorbBuf            = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
+    pThis->cbRirbBuf            = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
+
     /** @todo r=bird: There are probably other things which should be
      *        initialized here before we start failing. */
@@ -4670,10 +4643,10 @@
         LogRel(("HDA: Using custom position adjustment (%RU16 audio frames)\n", pThis->cPosAdjustFrames));
 
-    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThis->Dbg.fEnabled, false);
+    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("HDA configuration error: failed to read debugging enabled flag as boolean"));
 
-    rc = pHlp->pfnCFGMQueryStringDef(pCfg, "DebugPathOut", pThis->Dbg.szOutPath, sizeof(pThis->Dbg.szOutPath),
+    rc = pHlp->pfnCFGMQueryStringDef(pCfg, "DebugPathOut", pThisCC->Dbg.szOutPath, sizeof(pThisCC->Dbg.szOutPath),
                                      VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH);
     if (RT_FAILURE(rc))
@@ -4681,6 +4654,6 @@
                                 N_("HDA configuration error: failed to read debugging output path flag as string"));
 
-    if (pThis->Dbg.fEnabled)
-        LogRel2(("HDA: Debug output will be saved to '%s'\n", pThis->Dbg.szOutPath));
+    if (pThisCC->Dbg.fEnabled)
+        LogRel2(("HDA: Debug output will be saved to '%s'\n", pThisCC->Dbg.szOutPath));
 
     /*
@@ -4698,7 +4671,7 @@
      * Initialize data (most of it anyway).
      */
-    pThis->pDevInsR3                = pDevIns;
+    pThisCC->pDevIns                  = pDevIns;
     /* IBase */
-    pThis->IBase.pfnQueryInterface  = hdaR3QueryInterface;
+    pThisCC->IBase.pfnQueryInterface  = hdaR3QueryInterface;
 
     /* PCI Device */
@@ -4827,5 +4800,5 @@
         AssertBreak(iLun < UINT8_MAX);
         LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
-        rc = hdaR3AttachInternal(pThis, iLun, 0 /* fFlags */, NULL /* ppDrv */);
+        rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, 0 /* fFlags */, NULL /* ppDrv */);
         if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
         {
@@ -4835,5 +4808,5 @@
         if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
         {
-            hdaR3ReconfigLunWithNullAudio(pThis, iLun); /* Pretend attaching to the NULL audio backend will never fail. */
+            hdaR3ReconfigLunWithNullAudio(pDevIns, pThis, pThisCC, iLun); /* Pretend attaching to the NULL audio backend will never fail. */
             PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
                                        N_("Host audio backend initialization has failed. Selecting the NULL audio backend with the consequence that no sound is audible"));
@@ -4846,5 +4819,5 @@
      * Create the mixer.
      */
-    rc = AudioMixerCreate("HDA Mixer", 0 /* uFlags */, &pThis->pMixer);
+    rc = AudioMixerCreate("HDA Mixer", 0 /* uFlags */, &pThisCC->pMixer);
     AssertRCReturn(rc, rc);
 
@@ -4853,12 +4826,12 @@
      */
 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-    rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Front", AUDMIXSINKDIR_OUTPUT, &pThis->SinkFront.pMixSink);
+    rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] Front", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkFront.pMixSink);
     AssertRCReturn(rc, rc);
-    rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Center / Subwoofer", AUDMIXSINKDIR_OUTPUT, &pThis->SinkCenterLFE.pMixSink);
+    rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] Center / Subwoofer", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkCenterLFE.pMixSink);
     AssertRCReturn(rc, rc);
-    rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Rear", AUDMIXSINKDIR_OUTPUT, &pThis->SinkRear.pMixSink);
+    rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] Rear", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkRear.pMixSink);
     AssertRCReturn(rc, rc);
 #else
-    rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->SinkFront.pMixSink);
+    rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkFront.pMixSink);
     AssertRCReturn(rc, rc);
 #endif
@@ -4867,8 +4840,8 @@
      * Add mixer input sinks.
      */
-    rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->SinkLineIn.pMixSink);
+    rc = AudioMixerCreateSink(pThisCC->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThisCC->SinkLineIn.pMixSink);
     AssertRCReturn(rc, rc);
 #ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-    rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->SinkMicIn.pMixSink);
+    rc = AudioMixerCreateSink(pThisCC->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThisCC->SinkMicIn.pMixSink);
     AssertRCReturn(rc, rc);
 #endif
@@ -4876,39 +4849,29 @@
     /* There is no master volume control. Set the master to max. */
     PDMAUDIOVOLUME vol = { false, 255, 255 };
-    rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
+    rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &vol);
     AssertRCReturn(rc, rc);
 
-    /* Allocate CORB buffer. */
-    pThis->cbCorbBuf   = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
-    pThis->pu32CorbBuf = (uint32_t *)RTMemAllocZ(pThis->cbCorbBuf);
-    AssertReturn(pThis->pu32CorbBuf, VERR_NO_MEMORY);
-
-    /* Allocate RIRB buffer. */
-    pThis->cbRirbBuf   = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
-    pThis->pu64RirbBuf = (uint64_t *)RTMemAllocZ(pThis->cbRirbBuf);
-    AssertReturn(pThis->pu64RirbBuf, VERR_NO_MEMORY);
-
     /* Allocate codec. */
-    pThis->pCodec = (PHDACODEC)RTMemAllocZ(sizeof(HDACODEC));
-    AssertReturn(pThis->pCodec, VERR_NO_MEMORY);
+    PHDACODEC pCodec = (PHDACODEC)RTMemAllocZ(sizeof(HDACODEC));
+    pThisCC->pCodec = pCodec;
+    AssertReturn(pCodec, VERR_NO_MEMORY);
 
     /* Set codec callbacks to this controller. */
-    pThis->pCodec->pfnCbMixerAddStream    = hdaR3MixerAddStream;
-    pThis->pCodec->pfnCbMixerRemoveStream = hdaR3MixerRemoveStream;
-    pThis->pCodec->pfnCbMixerControl      = hdaR3MixerControl;
-    pThis->pCodec->pfnCbMixerSetVolume    = hdaR3MixerSetVolume;
-
-    pThis->pCodec->pHDAState = pThis; /* Assign HDA controller state to codec. */
+    pCodec->pDevIns                = pDevIns;
+    pCodec->pfnCbMixerAddStream    = hdaR3MixerAddStream;
+    pCodec->pfnCbMixerRemoveStream = hdaR3MixerRemoveStream;
+    pCodec->pfnCbMixerControl      = hdaR3MixerControl;
+    pCodec->pfnCbMixerSetVolume    = hdaR3MixerSetVolume;
 
     /* Construct the codec. */
-    rc = hdaCodecConstruct(pDevIns, pThis->pCodec, 0 /* Codec index */, pCfg);
+    rc = hdaCodecConstruct(pDevIns, pCodec, 0 /* Codec index */, pCfg);
     AssertRCReturn(rc, rc);
 
     /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for
        verb F20 should provide device/codec recognition. */
-    Assert(pThis->pCodec->u16VendorId);
-    Assert(pThis->pCodec->u16DeviceId);
-    PDMPciDevSetSubSystemVendorId(pPciDev, pThis->pCodec->u16VendorId); /* 2c ro - intel.) */
-    PDMPciDevSetSubSystemId(      pPciDev, pThis->pCodec->u16DeviceId); /* 2e ro. */
+    Assert(pCodec->u16VendorId);
+    Assert(pCodec->u16DeviceId);
+    PDMPciDevSetSubSystemVendorId(pPciDev, pCodec->u16VendorId); /* 2c ro - intel.) */
+    PDMPciDevSetSubSystemId(      pPciDev, pCodec->u16DeviceId); /* 2e ro. */
 
     /*
@@ -4930,5 +4893,5 @@
     for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
     {
-        rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, &pThis->aStreams[i],
+        rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
                                   TMTIMER_FLAGS_NO_CRIT_SECT, s_apszNames[i], &pThis->aStreams[i].hTimer);
         AssertRCReturn(rc, rc);
@@ -4943,5 +4906,5 @@
     for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
     {
-        rc = hdaR3StreamCreate(&pThis->aStreams[i], pThis, i /* u8SD */);
+        rc = hdaR3StreamConstruct(&pThis->aStreams[i], &pThisCC->aStreams[i], pThis, pThisCC, i /* u8SD */);
         AssertRCReturn(rc, rc);
     }
@@ -4952,5 +4915,5 @@
      */
     PHDADRIVER pDrv;
-    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+    RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
     {
         /*
@@ -5132,5 +5095,4 @@
      * Register statistics.
      */
-    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,            STAMTYPE_PROFILE, "Timer",             STAMUNIT_TICKS_PER_CALL, "Profiling hdaR3Timer.");
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn,               STAMTYPE_PROFILE, "Input",             STAMUNIT_TICKS_PER_CALL, "Profiling input.");
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut,              STAMTYPE_PROFILE, "Output",            STAMUNIT_TICKS_PER_CALL, "Profiling output.");
@@ -5203,5 +5165,5 @@
     /* .uSharedVersion = */         42,
     /* .cbInstanceShared = */       sizeof(HDASTATE),
-    /* .cbInstanceCC = */           0,
+    /* .cbInstanceCC = */           CTX_EXPR(sizeof(HDASTATER3), 0, 0),
     /* .cbInstanceRC = */           0,
     /* .cMaxPciDevices = */         1,
Index: /trunk/src/VBox/Devices/Audio/DevHDA.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.h	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.h	(revision 82450)
@@ -36,11 +36,12 @@
 
 /**
- * Structure defining an HDA mixer sink.
- * Its purpose is to know which audio mixer sink is bound to
- * which SDn (SDI/SDO) device stream.
- *
- * This is needed in order to handle interleaved streams
- * (that is, multiple channels in one stream) or non-interleaved
- * streams (each channel has a dedicated stream).
+ * HDA mixer sink definition (ring-3).
+ *
+ * Its purpose is to know which audio mixer sink is bound to which SDn
+ * (SDI/SDO) device stream.
+ *
+ * This is needed in order to handle interleaved streams (that is, multiple
+ * channels in one stream) or non-interleaved streams (each channel has a
+ * dedicated stream).
  *
  * This is only known to the actual device emulation level.
@@ -48,11 +49,14 @@
 typedef struct HDAMIXERSINK
 {
-    R3PTRTYPE(PHDASTREAM)   pStream;
+    R3PTRTYPE(PHDASTREAM)   pStreamShared;
+    R3PTRTYPE(PHDASTREAMR3) pStreamR3;
     /** Pointer to the actual audio mixer sink. */
     R3PTRTYPE(PAUDMIXSINK)  pMixSink;
-} HDAMIXERSINK, *PHDAMIXERSINK;
-
-/**
- * Mapping a stream tag to an HDA stream.
+} HDAMIXERSINK;
+/** Pointer to an HDA mixer sink definition (ring-3). */
+typedef HDAMIXERSINK *PHDAMIXERSINK;
+
+/**
+ * Mapping a stream tag to an HDA stream (ring-3).
  */
 typedef struct HDATAG
@@ -62,42 +66,9 @@
     uint8_t                 Padding[7];
     /** Pointer to associated stream. */
-    R3PTRTYPE(PHDASTREAM) pStream;
+    R3PTRTYPE(PHDASTREAMR3) pStreamR3;
 } HDATAG;
 /** Pointer to a HDA stream tag mapping. */
 typedef HDATAG *PHDATAG;
 
-/** @todo Make STAM values out of this? */
-typedef struct HDASTATEDEBUG
-{
-#ifdef DEBUG
-    /** Timestamp (in ns) of the last timer callback (hdaTimer).
-     * Used to calculate the time actually elapsed between two timer callbacks. */
-    uint64_t                tsTimerLastCalledNs;
-    /** IRQ debugging information. */
-    struct
-    {
-        /** Timestamp (in ns) of last processed (asserted / deasserted) IRQ. */
-        uint64_t            tsProcessedLastNs;
-        /** Timestamp (in ns) of last asserted IRQ. */
-        uint64_t            tsAssertedNs;
-        /** How many IRQs have been asserted already. */
-        uint64_t            cAsserted;
-        /** Accumulated elapsed time (in ns) of all IRQ being asserted. */
-        uint64_t            tsAssertedTotalNs;
-        /** Timestamp (in ns) of last deasserted IRQ. */
-        uint64_t            tsDeassertedNs;
-        /** How many IRQs have been deasserted already. */
-        uint64_t            cDeasserted;
-        /** Accumulated elapsed time (in ns) of all IRQ being deasserted. */
-        uint64_t            tsDeassertedTotalNs;
-    } IRQ;
-#endif
-    /** Whether debugging is enabled or not. */
-    bool                    fEnabled;
-    /** Path where to dump the debug output to.
-     *  Defaults to VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH. */
-    char                    szOutPath[RTPATH_MAX + 1];
-} HDASTATEDEBUG;
-
 /**
  * Shared ICH Intel HD audio controller state.
@@ -107,14 +78,8 @@
     /** Critical section protecting the HDA state. */
     PDMCRITSECT             CritSect;
-    /** R3 Pointer to the device instance. */
-    PPDMDEVINSR3            pDevInsR3;
-    /** The base interface for LUN\#0. */
-    PDMIBASE                IBase;
     /** The HDA's register set. */
     uint32_t                au32Regs[HDA_NUM_REGS];
     /** Internal stream states. */
     HDASTREAM               aStreams[HDA_MAX_STREAMS];
-    /** Mapping table between stream tags and stream states. */
-    HDATAG                  aTags[HDA_MAX_TAGS];
     /** CORB buffer base address. */
     uint64_t                u64CORBBase;
@@ -124,42 +89,8 @@
      *  Made out of DPLBASE + DPUBASE (3.3.32 + 3.3.33). */
     uint64_t                u64DPBase;
-    /** Pointer to CORB buffer. */
-    R3PTRTYPE(uint32_t *)   pu32CorbBuf;
-    /** Size in bytes of CORB buffer. */
+    /** Size in bytes of CORB buffer (#au32CorbBuf). */
     uint32_t                cbCorbBuf;
-    /** Padding for alignment. */
-    uint32_t                u32Padding1;
-    /** Pointer to RIRB buffer. */
-    R3PTRTYPE(uint64_t *)   pu64RirbBuf;
-    /** Size in bytes of RIRB buffer. */
+    /** Size in bytes of RIRB buffer (#au64RirbBuf). */
     uint32_t                cbRirbBuf;
-    /** DMA position buffer enable bit. */
-    bool                    fDMAPosition;
-    /** Reserved. */
-    bool                    afPadding1b[2];
-    /** Number of active (running) SDn streams. */
-    uint8_t                 cStreamsActive;
-    /** Pointer to HDA codec to use. */
-    R3PTRTYPE(PHDACODEC)    pCodec;
-    /** List of associated LUN drivers (HDADRIVER). */
-    RTLISTANCHORR3          lstDrv;
-    /** The device' software mixer. */
-    R3PTRTYPE(PAUDIOMIXER)  pMixer;
-    /** HDA sink for (front) output. */
-    HDAMIXERSINK            SinkFront;
-#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-    /** HDA sink for center / LFE output. */
-    HDAMIXERSINK            SinkCenterLFE;
-    /** HDA sink for rear output. */
-    HDAMIXERSINK            SinkRear;
-#endif
-    /** HDA mixer sink for line input. */
-    HDAMIXERSINK            SinkLineIn;
-#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-    /** Audio mixer sink for microphone input. */
-    HDAMIXERSINK            SinkMicIn;
-#endif
-    /** Last updated wall clock (WALCLK) counter. */
-    uint64_t                u64WalClk;
     /** Response Interrupt Count (RINTCNT). */
     uint16_t                u16RespIntCnt;
@@ -177,4 +108,8 @@
     /** Whether the position adjustment is enabled or not. */
     bool                    fPosAdjustEnabled;
+    /** DMA position buffer enable bit. */
+    bool                    fDMAPosition;
+    /** Current IRQ level. */
+    uint8_t                 u8IRQL;
 #ifdef VBOX_STRICT
     /** Wall clock (WALCLK) stale count.
@@ -182,16 +117,17 @@
      *  move the counter forward (stale). */
     uint8_t                 u8WalClkStaleCnt;
-    uint8_t                 Padding1[2];
 #else
-    uint8_t                 Padding1[3];
-#endif
-    /** Current IRQ level. */
-    uint8_t                 u8IRQL;
+    uint8_t                 bPadding1;
+#endif
     /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */
     uint16_t                uTimerHz;
     /** Padding for alignment. */
-    uint8_t                 au8Padding3[3];
-    /** Debug stuff. */
-    HDASTATEDEBUG           Dbg;
+    uint16_t                au16Padding3[3];
+    /** Last updated wall clock (WALCLK) counter. */
+    uint64_t                u64WalClk;
+    /** The CORB buffer. */
+    uint32_t                au32CorbBuf[HDA_CORB_SIZE];
+    /** Pointer to RIRB buffer. */
+    uint64_t                au64RirbBuf[HDA_RIRB_SIZE];
 
     /** PCI Region \#0: 16KB of MMIO stuff. */
@@ -199,5 +135,4 @@
 
 #ifdef VBOX_WITH_STATISTICS
-    STAMPROFILE             StatTimer;
     STAMPROFILE             StatIn;
     STAMPROFILE             StatOut;
@@ -224,4 +159,37 @@
     /** @} */
 #endif
+
+#ifdef DEBUG
+    /** Debug stuff.
+     * @todo Make STAM values out some of this? */
+    struct
+    {
+# if 0 /* unused */
+        /** Timestamp (in ns) of the last timer callback (hdaTimer).
+         * Used to calculate the time actually elapsed between two timer callbacks. */
+        uint64_t                tsTimerLastCalledNs;
+# endif
+        /** IRQ debugging information. */
+        struct
+        {
+            /** Timestamp (in ns) of last processed (asserted / deasserted) IRQ. */
+            uint64_t            tsProcessedLastNs;
+            /** Timestamp (in ns) of last asserted IRQ. */
+            uint64_t            tsAssertedNs;
+# if 0 /* unused */
+            /** How many IRQs have been asserted already. */
+            uint64_t            cAsserted;
+            /** Accumulated elapsed time (in ns) of all IRQ being asserted. */
+            uint64_t            tsAssertedTotalNs;
+            /** Timestamp (in ns) of last deasserted IRQ. */
+            uint64_t            tsDeassertedNs;
+            /** How many IRQs have been deasserted already. */
+            uint64_t            cDeasserted;
+            /** Accumulated elapsed time (in ns) of all IRQ being deasserted. */
+            uint64_t            tsDeassertedTotalNs;
+# endif
+        } IRQ;
+    } Dbg;
+#endif
     /** This is for checking that the build was correctly configured in all contexts.
      *  This is set to HDASTATE_ALIGNMENT_CHECK_MAGIC. */
@@ -234,4 +202,55 @@
 #define HDASTATE_ALIGNMENT_CHECK_MAGIC  UINT64_C(0x1298afb75893e059)
 
+
+/**
+ * Ring-3 ICH Intel HD audio controller state.
+ */
+typedef struct HDASTATER3
+{
+    /** Internal stream states. */
+    HDASTREAMR3             aStreams[HDA_MAX_STREAMS];
+    /** Mapping table between stream tags and stream states. */
+    HDATAG                  aTags[HDA_MAX_TAGS];
+    /** Number of active (running) SDn streams. */
+    uint8_t                 cStreamsActive;
+    uint8_t                 abPadding0[7];
+    /** R3 Pointer to the device instance. */
+    PPDMDEVINSR3            pDevIns;
+    /** The base interface for LUN\#0. */
+    PDMIBASE                IBase;
+    /** Pointer to HDA codec to use. */
+    R3PTRTYPE(PHDACODEC)    pCodec;
+    /** List of associated LUN drivers (HDADRIVER). */
+    RTLISTANCHORR3          lstDrv;
+    /** The device' software mixer. */
+    R3PTRTYPE(PAUDIOMIXER)  pMixer;
+    /** HDA sink for (front) output. */
+    HDAMIXERSINK            SinkFront;
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+    /** HDA sink for center / LFE output. */
+    HDAMIXERSINK            SinkCenterLFE;
+    /** HDA sink for rear output. */
+    HDAMIXERSINK            SinkRear;
+#endif
+    /** HDA mixer sink for line input. */
+    HDAMIXERSINK            SinkLineIn;
+#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
+    /** Audio mixer sink for microphone input. */
+    HDAMIXERSINK            SinkMicIn;
+#endif
+    /** Debug stuff. */
+    struct
+    {
+        /** Whether debugging is enabled or not. */
+        bool                    fEnabled;
+        /** Path where to dump the debug output to.
+         *  Defaults to VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH. */
+        char                    szOutPath[RTPATH_MAX];
+    } Dbg;
+} HDASTATER3;
+/** Pointer to a ring-3 HDA device state.  */
+typedef HDASTATER3 *PHDASTATER3;
+
+
 #endif /* !VBOX_INCLUDED_SRC_Audio_DevHDA_h */
 
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp	(revision 82450)
@@ -41,13 +41,12 @@
  * Processes (de/asserts) the interrupt according to the HDA's current state.
  *
- * @returns IPRT status code.
  * @param   pDevIns             The device instance.
- * @param   pThis               HDA state.
+ * @param   pThis               The shared HDA device state.
  * @param   pszSource           Caller information.
  */
 #if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING)
-int hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource)
+void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource)
 #else
-int hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis)
+void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis)
 #endif
 {
@@ -80,6 +79,4 @@
         pThis->u8IRQL = 0;
     }
-
-    return VINF_SUCCESS;
 }
 
@@ -89,5 +86,5 @@
  * @return  IPRT status code.
  * @return  Currently set wall clock value.
- * @param   pThis               HDA state.
+ * @param   pThis               The shared HDA device state.
  *
  * @remark  Operation is atomic.
@@ -99,4 +96,15 @@
 
 #ifdef IN_RING3
+
+/**
+ * Helper for hdaR3WalClkSet.
+ */
+DECLINLINE(PHDASTREAMPERIOD) hdaR3SinkToStreamPeriod(PHDAMIXERSINK pSink)
+{
+    PHDASTREAM pStream = hdaR3GetSharedStreamFromSink(pSink);
+    if (pStream)
+        return &pStream->State.Period;
+    return NULL;
+}
 
 /**
@@ -107,22 +115,22 @@
  *
  * @return  true if the WALCLK register has been updated, false if not.
- * @param   pThis               HDA state.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   u64WalClk           Wall clock value to set WALCLK register to.
  * @param   fForce              Whether to force setting the wall clock value or not.
  */
-bool hdaR3WalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce)
-{
-    const bool     fFrontPassed       = hdaR3StreamPeriodHasPassedAbsWalClk (&hdaR3GetStreamFromSink(pThis, &pThis->SinkFront)->State.Period,
-                                                                           u64WalClk);
-    const uint64_t u64FrontAbsWalClk  = hdaR3StreamPeriodGetAbsElapsedWalClk(&hdaR3GetStreamFromSink(pThis, &pThis->SinkFront)->State.Period);
+bool hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce)
+{
+    const bool     fFrontPassed       = hdaR3StreamPeriodHasPassedAbsWalClk( hdaR3SinkToStreamPeriod(&pThisCC->SinkFront), u64WalClk);
+    const uint64_t u64FrontAbsWalClk  = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkFront));
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
 #  error "Implement me!"
 # endif
 
-    const bool     fLineInPassed      = hdaR3StreamPeriodHasPassedAbsWalClk (&hdaR3GetStreamFromSink(pThis, &pThis->SinkLineIn)->State.Period, u64WalClk);
-    const uint64_t u64LineInAbsWalClk = hdaR3StreamPeriodGetAbsElapsedWalClk(&hdaR3GetStreamFromSink(pThis, &pThis->SinkLineIn)->State.Period);
+    const bool     fLineInPassed      = hdaR3StreamPeriodHasPassedAbsWalClk (hdaR3SinkToStreamPeriod(&pThisCC->SinkLineIn), u64WalClk);
+    const uint64_t u64LineInAbsWalClk = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkLineIn));
 # ifdef VBOX_WITH_HDA_MIC_IN
-    const bool     fMicInPassed       = hdaR3StreamPeriodHasPassedAbsWalClk (&hdaR3GetStreamFromSink(pThis, &pThis->SinkMicIn)->State.Period,  u64WalClk);
-    const uint64_t u64MicInAbsWalClk  = hdaR3StreamPeriodGetAbsElapsedWalClk(&hdaR3GetStreamFromSink(pThis, &pThis->SinkMicIn)->State.Period);
+    const bool     fMicInPassed       = hdaR3StreamPeriodHasPassedAbsWalClk (hdaR3SinkToStreamPeriod(&pThisCC->SinkMicIn),  u64WalClk);
+    const uint64_t u64MicInAbsWalClk  = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkMicIn));
 # endif
 
@@ -190,9 +198,9 @@
  *
  * @return  PHDAMIXERSINK
- * @param   pThis               HDA state.
+ * @param   pThisCC             The ring-3 HDA device state.
  * @param   uSD                 SD# to return mixer sink for.
  *                              NULL if not found / handled.
  */
-PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATE pThis, uint8_t uSD)
+PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATER3 pThisCC, uint8_t uSD)
 {
     if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN)
@@ -201,11 +209,11 @@
 
         if (uSD == uFirstSDI) /* First SDI. */
-            return &pThis->SinkLineIn;
+            return &pThisCC->SinkLineIn;
 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
         if (uSD == uFirstSDI + 1)
-            return &pThis->SinkMicIn;
+            return &pThisCC->SinkMicIn;
 # else
         /* If we don't have a dedicated Mic-In sink, use the always present Line-In sink. */
-        return &pThis->SinkLineIn;
+        return &pThisCC->SinkLineIn;
 # endif
     }
@@ -215,10 +223,10 @@
 
         if (uSD == uFirstSDO)
-            return &pThis->SinkFront;
+            return &pThisCC->SinkFront;
 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
         if (uSD == uFirstSDO + 1)
-            return &pThis->SinkCenterLFE;
+            return &pThisCC->SinkCenterLFE;
         if (uSD == uFirstSDO + 2)
-            return &pThis->SinkRear;
+            return &pThisCC->SinkRear;
 # endif
     }
@@ -270,30 +278,43 @@
  * @return  Pointer to HDA stream, or NULL if none found.
  */
-PHDASTREAM hdaR3GetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink)
-{
-    AssertPtrReturn(pThis, NULL);
+PHDASTREAMR3 hdaR3GetR3StreamFromSink(PHDAMIXERSINK pSink)
+{
     AssertPtrReturn(pSink, NULL);
 
     /** @todo Do something with the channel mapping here? */
-    return pSink->pStream;
-}
-
-/**
+    return pSink->pStreamR3;
+}
+
+
+/**
+ * Returns the HDA stream of specified HDA sink.
+ *
+ * @return  Pointer to HDA stream, or NULL if none found.
+ */
+PHDASTREAM hdaR3GetSharedStreamFromSink(PHDAMIXERSINK pSink)
+{
+    AssertPtrReturn(pSink, NULL);
+
+    /** @todo Do something with the channel mapping here? */
+    return pSink->pStreamShared;
+}
+
+/*
  * Reads DMA data from a given HDA output stream.
  *
  * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   pStream             HDA output stream to read DMA data from.
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state (for stats).
+ * @param   pStreamShared       HDA output stream to read DMA data from - shared bits.
+ * @param   pStreamR3           HDA output stream to read DMA data from - shared ring-3.
  * @param   pvBuf               Where to store the read data.
  * @param   cbBuf               How much to read in bytes.
  * @param   pcbRead             Returns read bytes from DMA. Optional.
  */
-int hdaR3DMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbRead is optional. */
-
-    PHDABDLE pBDLE       = &pStream->State.BDLE;
+int hdaR3DMARead(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3,
+                 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+{
+    RT_NOREF(pThis);
+    PHDABDLE pBDLE = &pStreamShared->State.BDLE;
 
     int rc = VINF_SUCCESS;
@@ -305,17 +326,16 @@
     uint64_t   csSilence = 0;
 
-    pStream->Dbg.cSilenceThreshold = 100;
-    pStream->Dbg.cbSilenceReadMin  = _1M;
-# endif
-
-    RTGCPHYS addrChunk = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff;
+    pStreamCC->Dbg.cSilenceThreshold = 100;
+    pStreamCC->Dbg.cbSilenceReadMin  = _1M;
+# endif
+
+    RTGCPHYS GCPhysChunk = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff;
 
     while (cbLeft)
     {
-        uint32_t cbChunk = RT_MIN(cbLeft, pStream->u16FIFOS);
-
-        rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), addrChunk, (uint8_t *)pvBuf + cbReadTotal, cbChunk);
-        if (RT_FAILURE(rc))
-            break;
+        uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u16FIFOS);
+
+        rc = PDMDevHlpPhysRead(pDevIns, GCPhysChunk, (uint8_t *)pvBuf + cbReadTotal, cbChunk);
+        AssertRCBreak(rc);
 
 # ifdef HDA_DEBUG_SILENCE
@@ -330,26 +350,28 @@
         }
 # endif
-        if (pStream->Dbg.Runtime.fEnabled)
-            DrvAudioHlpFileWrite(pStream->Dbg.Runtime.pFileDMARaw, (uint8_t *)pvBuf + cbReadTotal, cbChunk, 0 /* fFlags */);
+        if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
+        { /* likely */ }
+        else
+            DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, (uint8_t *)pvBuf + cbReadTotal, cbChunk, 0 /* fFlags */);
 
         STAM_COUNTER_ADD(&pThis->StatBytesRead, cbChunk);
-        addrChunk         = (addrChunk + cbChunk) % pBDLE->Desc.u32BufSize;
-
+
+        /* advance */
         Assert(cbLeft    >= cbChunk);
+        GCPhysChunk       = (GCPhysChunk + cbChunk) % pBDLE->Desc.u32BufSize;
+        cbReadTotal      += cbChunk;
         cbLeft           -= cbChunk;
-
-        cbReadTotal      += cbChunk;
     }
 
 # ifdef HDA_DEBUG_SILENCE
     if (csSilence)
-        pStream->Dbg.csSilence += csSilence;
+        pStreamR3->Dbg.csSilence += csSilence;
 
     if (   csSilence == 0
-        && pStream->Dbg.csSilence   >  pStream->Dbg.cSilenceThreshold
-        && pStream->Dbg.cbReadTotal >= pStream->Dbg.cbSilenceReadMin)
-    {
-        LogFunc(("Silent block detected: %RU64 audio samples\n", pStream->Dbg.csSilence));
-        pStream->Dbg.csSilence = 0;
+        && pStreamR3->Dbg.csSilence   >  pStreamR3->Dbg.cSilenceThreshold
+        && pStreamR3->Dbg.cbReadTotal >= pStreamR3->Dbg.cbSilenceReadMin)
+    {
+        LogFunc(("Silent block detected: %RU64 audio samples\n", pStreamR3->Dbg.csSilence));
+        pStreamR3->Dbg.csSilence = 0;
     }
 # endif
@@ -368,47 +390,43 @@
  *
  * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   pStream             HDA input stream to write audio data to.
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state (for stats).
+ * @param   pStreamShared       HDA input stream to write audio data to - shared.
+ * @param   pStreamR3           HDA input stream to write audio data to - ring-3.
  * @param   pvBuf               Data to write.
  * @param   cbBuf               How much (in bytes) to write.
  * @param   pcbWritten          Returns written bytes on success. Optional.
  */
-int hdaR3DMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbWritten is optional. */
-
-    PHDABDLE pBDLE  = &pStream->State.BDLE;
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbWrittenTotal = 0;
-    uint32_t cbLeft = RT_MIN(cbBuf, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
-
-    RTGCPHYS addrChunk = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff;
-
+int hdaR3DMAWrite(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3,
+                  const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+{
+    RT_NOREF(pThis);
+    PHDABDLE    pBDLE          = &pStreamShared->State.BDLE;
+    int         rc             = VINF_SUCCESS;
+    uint32_t    cbWrittenTotal = 0;
+    uint32_t    cbLeft         = RT_MIN(cbBuf, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
+    RTGCPHYS    GCPhysChunk    = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff;
     while (cbLeft)
     {
-        uint32_t cbChunk = RT_MIN(cbLeft, pStream->u16FIFOS);
+        uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u16FIFOS);
 
         /* Sanity checks. */
         Assert(cbChunk <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
 
-        if (pStream->Dbg.Runtime.fEnabled)
-            DrvAudioHlpFileWrite(pStream->Dbg.Runtime.pFileDMARaw, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk, 0 /* fFlags */);
-
-        rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
-                                   addrChunk, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk);
-        if (RT_FAILURE(rc))
-            break;
+        if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
+        { /* likely */ }
+        else
+            DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk, 0 /* fFlags */);
+
+        rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysChunk, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk);
+        AssertRCReturn(rc, rc);
 
         STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbChunk);
-        addrChunk       = (addrChunk + cbChunk) % pBDLE->Desc.u32BufSize;
-
+
+        /* advance */
         Assert(cbLeft  >= cbChunk);
-        cbLeft -= (uint32_t)cbChunk;
-
         cbWrittenTotal += (uint32_t)cbChunk;
+        GCPhysChunk     = (GCPhysChunk + cbChunk) % pBDLE->Desc.u32BufSize;
+        cbLeft         -= (uint32_t)cbChunk;
     }
 
@@ -430,5 +448,5 @@
  *
  * @returns Determined INTSTS register value.
- * @param   pThis               HDA state.
+ * @param   pThis               The shared HDA device state.
  *
  * @remark  This function does *not* set INTSTS!
@@ -554,5 +572,5 @@
 
 # ifdef LOG_ENABLED
-void hdaR3BDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
+void hdaR3BDLEDumpAll(PPDMDEVINS pDevIns, PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
 {
     LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE));
@@ -564,5 +582,5 @@
     {
         HDABDLEDESC bd;
-        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
+        PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
 
         LogFunc(("\t#%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n",
@@ -582,5 +600,5 @@
     {
         uint32_t uDMACnt;
-        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
+        PDMDevHlpPhysRead(pDevIns, (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
                           &uDMACnt, sizeof(uDMACnt));
 
@@ -593,12 +611,11 @@
  * Fetches a Bundle Descriptor List Entry (BDLE) from the DMA engine.
  *
- * @param   pThis                   Pointer to HDA state.
- * @param   pBDLE                   Where to store the fetched result.
- * @param   u64BaseDMA              Address base of DMA engine to use.
- * @param   u16Entry                BDLE entry to fetch.
- */
-int hdaR3BDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
+ * @param   pDevIns             The device instance.
+ * @param   pBDLE               Where to store the fetched result.
+ * @param   u64BaseDMA          Address base of DMA engine to use.
+ * @param   u16Entry            BDLE entry to fetch.
+ */
+int hdaR3BDLEFetch(PPDMDEVINS pDevIns, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry)
+{
     AssertPtrReturn(pBDLE,   VERR_INVALID_POINTER);
     AssertReturn(u64BaseDMA, VERR_INVALID_PARAMETER);
@@ -611,5 +628,5 @@
     /** @todo Compare u16Entry with LVI. */
 
-    int rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + (u16Entry * sizeof(HDABDLEDESC)),
+    int rc = PDMDevHlpPhysRead(pDevIns, u64BaseDMA + (u16Entry * sizeof(HDABDLEDESC)),
                                &pBDLE->Desc, sizeof(pBDLE->Desc));
 
@@ -664,9 +681,9 @@
  *
  * @returns Whether the new expiration time was set or not.
- * @param   pDevIns     The device instance.
- * @param   pStream     HDA stream to set timer for.
- * @param   tsExpire    New (virtual) expiration time to set.
- * @param   fForce      Whether to force setting the expiration time or not.
- * @param   tsNow       The current clock timestamp if available, 0 if not.
+ * @param   pDevIns         The device instance.
+ * @param   pStreamShared   HDA stream to set timer for (shared).
+ * @param   tsExpire        New (virtual) expiration time to set.
+ * @param   fForce          Whether to force setting the expiration time or not.
+ * @param   tsNow           The current clock timestamp if available, 0 if not.
  *
  * @remark  This function takes all active HDA streams and their
@@ -679,10 +696,10 @@
  *          Forcing a new expiration time will override the above mechanism.
  */
-bool hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint64_t tsExpire, bool fForce, uint64_t tsNow)
-{
-    AssertPtr(pStream);
+bool hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTREAM pStreamShared, uint64_t tsExpire, bool fForce, uint64_t tsNow)
+{
+    AssertPtr(pStreamShared);
 
     if (!tsNow)
-        tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
+        tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
 
     if (!fForce)
@@ -691,7 +708,7 @@
          * PDMDevHlpTimerGet(), so, some callers does one, this does, and then we do
          * right afterwards == very inefficient! */
-        if (hdaR3StreamTransferIsScheduled(pStream, tsNow))
+        if (hdaR3StreamTransferIsScheduled(pStreamShared, tsNow))
         {
-            uint64_t const tsNext = hdaR3StreamTransferGetNext(pStream);
+            uint64_t const tsNext = hdaR3StreamTransferGetNext(pStreamShared);
             if (tsExpire > tsNext)
                 tsExpire = tsNext;
@@ -706,5 +723,5 @@
         tsExpire = tsNow;
 
-    int rc = PDMDevHlpTimerSet(pDevIns, pStream->hTimer, tsExpire);
+    int rc = PDMDevHlpTimerSet(pDevIns, pStreamShared->hTimer, tsExpire);
     AssertRCReturn(rc, false);
 
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 82450)
@@ -25,7 +25,12 @@
 #include <VBox/log.h> /* LOG_ENABLED */
 
-    /** Read callback. */
+/** Pointer to an HDA stream (SDI / SDO).  */
+typedef struct HDASTREAMR3 *PHDASTREAMR3;
+
+
+
+/** Read callback. */
 typedef VBOXSTRICTRC FNHDAREGREAD(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-    /** Write callback. */
+/** Write callback. */
 typedef VBOXSTRICTRC FNHDAREGWRITE(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
 
@@ -598,10 +603,11 @@
  */
 #ifdef IN_RING3
-PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATE pThis, uint8_t uSD);
+PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATER3 pThisCC, uint8_t uSD);
 #endif
 PDMAUDIODIR   hdaGetDirFromSD(uint8_t uSD);
-PHDASTREAM    hdaGetStreamFromSD(PHDASTATE pThis, uint8_t uSD);
+//PHDASTREAM    hdaGetStreamFromSD(PHDASTATER3 pThisCC, uint8_t uSD);
 #ifdef IN_RING3
-PHDASTREAM    hdaR3GetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink);
+PHDASTREAMR3  hdaR3GetR3StreamFromSink(PHDAMIXERSINK pSink);
+PHDASTREAM    hdaR3GetSharedStreamFromSink(PHDAMIXERSINK pSink);
 #endif
 /** @} */
@@ -610,9 +616,9 @@
  * @{
  */
-#ifdef LOG_ENABLED
-int           hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource);
+#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING)
+void          hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource);
 # define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis)  hdaProcessInterrupt((a_pDevIns), (a_pThis), __FUNCTION__)
 #else
-int           hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis);
+void          hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis);
 # define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis)  hdaProcessInterrupt((a_pDevIns), (a_pThis))
 #endif
@@ -624,5 +630,5 @@
 uint64_t      hdaWalClkGetCurrent(PHDASTATE pThis);
 #ifdef IN_RING3
-bool          hdaR3WalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce);
+bool          hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce);
 #endif
 /** @} */
@@ -632,6 +638,8 @@
  */
 #ifdef IN_RING3
-int           hdaR3DMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
-int           hdaR3DMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
+int           hdaR3DMARead(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3,
+                           void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
+int           hdaR3DMAWrite(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3,
+                            const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
 #endif
 /** @} */
@@ -651,7 +659,7 @@
 #ifdef IN_RING3
 # ifdef LOG_ENABLED
-void          hdaR3BDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE);
+void          hdaR3BDLEDumpAll(PPDMDEVINS pDevIns, PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE);
 # endif
-int           hdaR3BDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
+int           hdaR3BDLEFetch(PPDMDEVINS pDevIns, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
 bool          hdaR3BDLEIsComplete(PHDABDLE pBDLE);
 bool          hdaR3BDLENeedsInterrupt(PHDABDLE pBDLE);
@@ -663,5 +671,5 @@
  */
 #ifdef IN_RING3
-bool          hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint64_t u64Expire, bool fForce, uint64_t tsNow);
+bool          hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTREAM pStreamShared, uint64_t u64Expire, bool fForce, uint64_t tsNow);
 #endif
 /** @} */
Index: /trunk/src/VBox/Devices/Audio/HDACodec.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDACodec.cpp	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/HDACodec.cpp	(revision 82450)
@@ -1631,5 +1631,5 @@
              DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
 
-    return pThis->pfnCbMixerSetVolume(pThis->pHDAState, enmMixerCtl, &Vol);
+    return pThis->pfnCbMixerSetVolume(pThis->pDevIns, enmMixerCtl, &Vol);
 }
 
@@ -2412,15 +2412,15 @@
 
             /* Propagate to the controller. */
-            pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_FRONT,      uSD, uChannel);
+            pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_FRONT,      uSD, uChannel);
 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-            pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
-            pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_REAR,       uSD, uChannel);
+            pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
+            pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_REAR,       uSD, uChannel);
 #endif
         }
         else if (enmDir == PDMAUDIODIR_IN)
         {
-            pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_LINE_IN,    uSD, uChannel);
+            pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_LINE_IN,    uSD, uChannel);
 #ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-            pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_MIC_IN,     uSD, uChannel);
+            pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_MIC_IN,     uSD, uChannel);
 #endif
         }
@@ -3065,14 +3065,12 @@
         case PDMAUDIOMIXERCTL_REAR:
 #endif
-        {
             break;
-        }
+
         case PDMAUDIOMIXERCTL_LINE_IN:
 #ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
         case PDMAUDIOMIXERCTL_MIC_IN:
 #endif
-        {
             break;
-        }
+
         default:
             AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
@@ -3082,5 +3080,5 @@
 
     if (RT_SUCCESS(rc))
-        rc = pThis->pfnCbMixerAddStream(pThis->pHDAState, enmMixerCtl, pCfg);
+        rc = pThis->pfnCbMixerAddStream(pThis->pDevIns, enmMixerCtl, pCfg);
 
     LogFlowFuncLeaveRC(rc);
@@ -3092,5 +3090,5 @@
     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
 
-    int rc = pThis->pfnCbMixerRemoveStream(pThis->pHDAState, enmMixerCtl);
+    int rc = pThis->pfnCbMixerRemoveStream(pThis->pDevIns, enmMixerCtl);
 
     LogFlowFuncLeaveRC(rc);
Index: /trunk/src/VBox/Devices/Audio/HDACodec.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDACodec.h	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/HDACodec.h	(revision 82450)
@@ -26,13 +26,12 @@
 #include "AudioMixer.h"
 
-/** The ICH HDA (Intel) controller. */
+/** Pointer to a shared HDA device state.  */
 typedef struct HDASTATE *PHDASTATE;
+/** Pointer to a ring-3 HDA device state.  */
+typedef struct HDASTATER3 *PHDASTATER3;
 /** The ICH HDA (Intel) codec state. */
 typedef struct HDACODEC *PHDACODEC;
 /** The HDA host driver backend. */
 typedef struct HDADRIVER *PHDADRIVER;
-typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR;
-typedef struct PDMAUDIOGSTSTRMOUT *PPDMAUDIOGSTSTRMOUT;
-typedef struct PDMAUDIOGSTSTRMIN  *PPDMAUDIOGSTSTRMIN;
 
 /**
@@ -41,5 +40,4 @@
 typedef DECLCALLBACK(int) FNHDACODECVERBPROCESSOR(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp);
 typedef FNHDACODECVERBPROCESSOR *PFNHDACODECVERBPROCESSOR;
-typedef FNHDACODECVERBPROCESSOR **PPFNHDACODECVERBPROCESSOR;
 
 /* PRM 5.3.1 */
@@ -71,4 +69,5 @@
     uint8_t                 u8BSKU;
     uint8_t                 u8AssemblyId;
+
     /** List of assigned HDA drivers to this codec.
      * A driver only can be assigned to one codec at a time. */
@@ -79,10 +78,12 @@
 
     PCODECNODE              paNodes;
-    /** Pointer to HDA state (controller) this
-     *  codec is assigned to. */
-    PHDASTATE               pHDAState;
+
     bool                    fInReset;
+    uint8_t                 abPadding1[3];
 
     const uint8_t           cTotalNodes;
+    const uint8_t           u8AdcVolsLineIn;
+    const uint8_t           u8DacLineOut;
+    uint8_t                 bPadding2;
     const uint8_t          *au8Ports;
     const uint8_t          *au8Dacs;
@@ -98,6 +99,4 @@
     const uint8_t          *au8VolKnobs;
     const uint8_t          *au8Reserveds;
-    const uint8_t           u8AdcVolsLineIn;
-    const uint8_t           u8DacLineOut;
 
     /** @name Public codec functions.
@@ -106,19 +105,56 @@
     DECLR3CALLBACKMEMBER(void, pfnReset, (PHDACODEC pThis));
     DECLR3CALLBACKMEMBER(int,  pfnNodeReset, (PHDACODEC pThis, uint8_t, PCODECNODE));
+    DECLR3CALLBACKMEMBER(void, pfnDbgListNodes, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs));
+    DECLR3CALLBACKMEMBER(void, pfnDbgSelector, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs));
     /** @} */
+
+    /** The parent device instance. */
+    PPDMDEVINS              pDevIns;
 
     /** @name Callbacks to the HDA controller, mostly used for multiplexing to the
      *        various host backends.
      * @{ */
-    DECLR3CALLBACKMEMBER(int,  pfnCbMixerAddStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg));
-    DECLR3CALLBACKMEMBER(int,  pfnCbMixerRemoveStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl));
-    DECLR3CALLBACKMEMBER(int,  pfnCbMixerControl, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel));
-    DECLR3CALLBACKMEMBER(int,  pfnCbMixerSetVolume, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol));
-    /** @} */
-
-    /** @name These callbacks are set by codec implementation to answer debugger requests.
-     * @{ */
-    DECLR3CALLBACKMEMBER(void, pfnDbgListNodes, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs));
-    DECLR3CALLBACKMEMBER(void, pfnDbgSelector, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs));
+    /**
+     *
+     * 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  VBox status code.
+     * @param   pThisCC             The ring-3 HDA device state.
+     * @param   enmMixerCtl         Mixer control to assign new stream to.
+     * @param   pCfg                Stream configuration for the new stream.
+     */
+    DECLR3CALLBACKMEMBER(int,  pfnCbMixerAddStream, (PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg));
+    /**
+     * Removes a specified mixer control from the HDA's mixer.
+     *
+     * @return  VBox status code.
+     * @param   pThisCC             The ring-3 HDA device state.
+     * @param   enmMixerCtl         Mixer control to remove.
+     */
+    DECLR3CALLBACKMEMBER(int,  pfnCbMixerRemoveStream, (PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl));
+    /**
+     * Controls an input / output converter widget, that is, which converter is
+     * connected to which stream (and channel).
+     *
+     * @return  VBox status code.
+     * @param   pThisCC             The ring-3 HDA device state.
+     * @param   enmMixerCtl         Mixer control to set SD stream number and channel for.
+     * @param   uSD                 SD stream number (number + 1) to set. Set to 0 for unassign.
+     * @param   uChannel            Channel to set. Only valid if a valid SD stream number is specified.
+     */
+    DECLR3CALLBACKMEMBER(int,  pfnCbMixerControl, (PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel));
+    /**
+     * Sets the volume of a specified mixer control.
+     *
+     * @return  IPRT status code.
+     * @param   pThisCC             The ring-3 HDA device state.
+     * @param   enmMixerCtl         Mixer control to set volume for.
+     * @param   pVol                Pointer to volume data to set.
+     */
+    DECLR3CALLBACKMEMBER(int,  pfnCbMixerSetVolume, (PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol));
     /** @} */
 
Index: /trunk/src/VBox/Devices/Audio/HDAStream.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 82450)
@@ -36,5 +36,15 @@
 
 
-#ifdef IN_RING3
+#ifdef IN_RING3 /* whole file */
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static void hdaR3StreamSetPosition(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB);
+
+static int  hdaR3StreamAsyncIODestroy(PHDASTREAMR3 pStreamR3);
+static int  hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3);
+
+
 
 /**
@@ -42,86 +52,92 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to create.
- * @param   pThis               HDA state to assign the HDA stream to.
- * @param   u8SD                Stream descriptor number to assign.
- */
-int hdaR3StreamCreate(PHDASTREAM pStream, PHDASTATE pThis, uint8_t u8SD)
+ * @param   pStreamShared       The HDA stream to construct - shared bits.
+ * @param   pStreamR3           The HDA stream to construct - ring-3 bits.
+ * @param   pThis               The shared HDA device instance.
+ * @param   pThisCC             The ring-3 HDA device instance.
+ * @param   uSD                 Stream descriptor number to assign.
+ */
+int hdaR3StreamConstruct(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PHDASTATE pThis, PHDASTATER3 pThisCC, uint8_t uSD)
 {
     int rc;
-    RT_NOREF(pThis);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    pStream->u8SD           = u8SD;
-    pStream->pMixSink       = NULL;
-    pStream->pHDAState      = pThis;
-    Assert(pStream->hTimer != NIL_TMTIMERHANDLE); /* hdaR3Construct initalized this one already. */
-
-    pStream->State.fInReset = false;
-    pStream->State.fRunning = false;
+
+    pStreamR3->u8SD             = uSD;
+    pStreamShared->u8SD         = uSD;
+    pStreamR3->pMixSink         = NULL;
+    pStreamR3->pHDAStateShared  = pThis;
+    pStreamR3->pHDAStateR3      = pThisCC;
+    Assert(pStreamShared->hTimer != NIL_TMTIMERHANDLE); /* hdaR3Construct initalized this one already. */
+
+    pStreamShared->State.fInReset = false;
+    pStreamShared->State.fRunning = false;
 #ifdef HDA_USE_DMA_ACCESS_HANDLER
-    RTListInit(&pStream->State.lstDMAHandlers);
+    RTListInit(&pStreamR3->State.lstDMAHandlers);
 #endif
 
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    rc = RTCritSectInit(&pStream->CritSect);
+    rc = RTCritSectInit(&pStreamR3->CritSect);
     AssertRCReturn(rc, rc);
 # endif
 
-    rc = hdaR3StreamPeriodCreate(&pStream->State.Period);
+    rc = hdaR3StreamPeriodCreate(&pStreamShared->State.Period);
     AssertRCReturn(rc, rc);
 
-    pStream->State.tsLastUpdateNs = 0;
+    pStreamShared->State.tsLastUpdateNs = 0;
 
 #ifdef DEBUG
-    rc = RTCritSectInit(&pStream->Dbg.CritSect);
+    rc = RTCritSectInit(&pStreamR3->Dbg.CritSect);
     AssertRCReturn(rc, rc);
 #endif
 
-    pStream->Dbg.Runtime.fEnabled = pThis->Dbg.fEnabled;
-
-    if (pStream->Dbg.Runtime.fEnabled)
+    pStreamR3->Dbg.Runtime.fEnabled = pThisCC->Dbg.fEnabled;
+
+    if (pStreamR3->Dbg.Runtime.fEnabled)
     {
         char szFile[64];
-
-        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
-            RTStrPrintf(szFile, sizeof(szFile), "hdaStreamWriteSD%RU8", pStream->u8SD);
+        char szPath[RTPATH_MAX];
+
+        /* pFileStream */
+        if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN)
+            RTStrPrintf(szFile, sizeof(szFile), "hdaStreamWriteSD%RU8", uSD);
         else
-            RTStrPrintf(szFile, sizeof(szFile), "hdaStreamReadSD%RU8", pStream->u8SD);
-
-        char szPath[RTPATH_MAX + 1];
-        int rc2 = DrvAudioHlpFileNameGet(szPath, sizeof(szPath), pThis->Dbg.szOutPath, szFile,
+            RTStrPrintf(szFile, sizeof(szFile), "hdaStreamReadSD%RU8", uSD);
+
+        int rc2 = DrvAudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.szOutPath, szFile,
                                          0 /* uInst */, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
         AssertRC(rc2);
-        rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAGS_NONE, &pStream->Dbg.Runtime.pFileStream);
+
+        rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAGS_NONE, &pStreamR3->Dbg.Runtime.pFileStream);
         AssertRC(rc2);
 
-        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
-            RTStrPrintf(szFile, sizeof(szFile), "hdaDMARawWriteSD%RU8", pStream->u8SD);
+        /* pFileDMARaw */
+        if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN)
+            RTStrPrintf(szFile, sizeof(szFile), "hdaDMARawWriteSD%RU8", uSD);
         else
-            RTStrPrintf(szFile, sizeof(szFile), "hdaDMARawReadSD%RU8", pStream->u8SD);
-
-        rc2 = DrvAudioHlpFileNameGet(szPath, sizeof(szPath), pThis->Dbg.szOutPath, szFile,
+            RTStrPrintf(szFile, sizeof(szFile), "hdaDMARawReadSD%RU8", uSD);
+
+        rc2 = DrvAudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.szOutPath, szFile,
                                      0 /* uInst */, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
         AssertRC(rc2);
 
-        rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAGS_NONE, &pStream->Dbg.Runtime.pFileDMARaw);
+        rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAGS_NONE, &pStreamR3->Dbg.Runtime.pFileDMARaw);
         AssertRC(rc2);
 
-        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
-            RTStrPrintf(szFile, sizeof(szFile), "hdaDMAWriteMappedSD%RU8", pStream->u8SD);
+        /* pFileDMAMapped */
+        if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN)
+            RTStrPrintf(szFile, sizeof(szFile), "hdaDMAWriteMappedSD%RU8", uSD);
         else
-            RTStrPrintf(szFile, sizeof(szFile), "hdaDMAReadMappedSD%RU8", pStream->u8SD);
-
-        rc2 = DrvAudioHlpFileNameGet(szPath, sizeof(szPath), pThis->Dbg.szOutPath, szFile,
+            RTStrPrintf(szFile, sizeof(szFile), "hdaDMAReadMappedSD%RU8", uSD);
+
+        rc2 = DrvAudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.szOutPath, szFile,
                                      0 /* uInst */, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
         AssertRC(rc2);
 
-        rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAGS_NONE, &pStream->Dbg.Runtime.pFileDMAMapped);
+        rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAGS_NONE, &pStreamR3->Dbg.Runtime.pFileDMAMapped);
         AssertRC(rc2);
 
         /* Delete stale debugging files from a former run. */
-        DrvAudioHlpFileDelete(pStream->Dbg.Runtime.pFileStream);
-        DrvAudioHlpFileDelete(pStream->Dbg.Runtime.pFileDMARaw);
-        DrvAudioHlpFileDelete(pStream->Dbg.Runtime.pFileDMAMapped);
+        DrvAudioHlpFileDelete(pStreamR3->Dbg.Runtime.pFileStream);
+        DrvAudioHlpFileDelete(pStreamR3->Dbg.Runtime.pFileDMARaw);
+        DrvAudioHlpFileDelete(pStreamR3->Dbg.Runtime.pFileDMAMapped);
     }
 
@@ -132,55 +148,54 @@
  * Destroys an HDA stream.
  *
- * @param   pStream             HDA stream to destroy.
- */
-void hdaR3StreamDestroy(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
-
-    LogFlowFunc(("[SD%RU8] Destroying ...\n", pStream->u8SD));
-
-    hdaR3StreamMapDestroy(&pStream->State.Mapping);
+ * @param   pStreamShared       The HDA stream to destroy - shared bits.
+ * @param   pStreamR3           The HDA stream to destroy - ring-3 bits.
+ */
+void hdaR3StreamDestroy(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
+{
+    LogFlowFunc(("[SD%RU8] Destroying ...\n", pStreamShared->u8SD));
+
+    hdaR3StreamMapDestroy(&pStreamR3->State.Mapping);
 
     int rc2;
 
 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    rc2 = hdaR3StreamAsyncIODestroy(pStream);
+    rc2 = hdaR3StreamAsyncIODestroy(pStreamR3);
     AssertRC(rc2);
 #endif
 
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    if (RTCritSectIsInitialized(&pStream->CritSect))
-    {
-        rc2 = RTCritSectDelete(&pStream->CritSect);
+    if (RTCritSectIsInitialized(&pStreamR3->CritSect))
+    {
+        rc2 = RTCritSectDelete(&pStreamR3->CritSect);
         AssertRC(rc2);
     }
 # endif
 
-    if (pStream->State.pCircBuf)
-    {
-        RTCircBufDestroy(pStream->State.pCircBuf);
-        pStream->State.pCircBuf = NULL;
-    }
-
-    hdaR3StreamPeriodDestroy(&pStream->State.Period);
+    if (pStreamR3->State.pCircBuf)
+    {
+        RTCircBufDestroy(pStreamR3->State.pCircBuf);
+        pStreamR3->State.pCircBuf = NULL;
+    }
+
+    hdaR3StreamPeriodDestroy(&pStreamShared->State.Period);
 
 #ifdef DEBUG
-    if (RTCritSectIsInitialized(&pStream->Dbg.CritSect))
-    {
-        rc2 = RTCritSectDelete(&pStream->Dbg.CritSect);
+    if (RTCritSectIsInitialized(&pStreamR3->Dbg.CritSect))
+    {
+        rc2 = RTCritSectDelete(&pStreamR3->Dbg.CritSect);
         AssertRC(rc2);
     }
 #endif
 
-    if (pStream->Dbg.Runtime.fEnabled)
-    {
-        DrvAudioHlpFileDestroy(pStream->Dbg.Runtime.pFileStream);
-        pStream->Dbg.Runtime.pFileStream = NULL;
-
-        DrvAudioHlpFileDestroy(pStream->Dbg.Runtime.pFileDMARaw);
-        pStream->Dbg.Runtime.pFileDMARaw = NULL;
-
-        DrvAudioHlpFileDestroy(pStream->Dbg.Runtime.pFileDMAMapped);
-        pStream->Dbg.Runtime.pFileDMAMapped = NULL;
+    if (pStreamR3->Dbg.Runtime.fEnabled)
+    {
+        DrvAudioHlpFileDestroy(pStreamR3->Dbg.Runtime.pFileStream);
+        pStreamR3->Dbg.Runtime.pFileStream = NULL;
+
+        DrvAudioHlpFileDestroy(pStreamR3->Dbg.Runtime.pFileDMARaw);
+        pStreamR3->Dbg.Runtime.pFileDMARaw = NULL;
+
+        DrvAudioHlpFileDestroy(pStreamR3->Dbg.Runtime.pFileDMAMapped);
+        pStreamR3->Dbg.Runtime.pFileDMAMapped = NULL;
     }
 
@@ -189,18 +204,21 @@
 
 /**
- * Initializes an HDA stream.
- *
- * @returns IPRT status code. VINF_NO_CHANGE if the stream does not need (re-)initialization because the stream's (hardware)
- *          parameters did not change.
- * @param   pDevIns The device instance.
- * @param   pStream HDA stream to initialize.
- * @param   uSD     SD (stream descriptor) number to assign the HDA stream to.
- */
-int hdaR3StreamInit(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint8_t uSD)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    PHDASTATE pThis = pStream->pHDAState;
-    AssertPtr(pThis);
+ * Sets up ((re-)iniitalizes) an HDA stream.
+ *
+ * @returns IPRT status code. VINF_NO_CHANGE if the stream does not need
+ *          be set-up again because the stream's (hardware) parameters did
+ *          not change.
+ * @param   pDevIns         The device instance.
+ * @param   pThis           The shared HDA device state (for HW register
+ *                          parameters).
+ * @param   pStreamShared   HDA stream to set up, shared portion.
+ * @param   pStreamR3       HDA stream to set up, ring-3 portion.
+ * @param   uSD             Stream descriptor number to assign it.
+ */
+int hdaR3StreamSetUp(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD)
+{
+    /* These member can only change on data corruption, despite what the code does further down (bird).  */
+    Assert(pStreamShared->u8SD == uSD);
+    Assert(pStreamR3->u8SD     == uSD);
 
     const uint64_t u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, uSD),
@@ -232,5 +250,5 @@
 
     /* Reset (any former) stream map. */
-    hdaR3StreamMapReset(&pStream->State.Mapping);
+    hdaR3StreamMapReset(&pStreamR3->State.Mapping);
 
     /*
@@ -242,9 +260,11 @@
      * number of channels in a single audio stream.
      */
-    rc = hdaR3StreamMapInit(&pStream->State.Mapping, &Props);
+    rc = hdaR3StreamMapInit(&pStreamR3->State.Mapping, &Props);
     AssertRCReturn(rc, rc);
 
-    ASSERT_GUEST_LOGREL_MSG_RETURN(u32CBL % pStream->State.Mapping.cbFrameSize == 0,
-                                   ("CBL for stream #%RU8 does not align to frame size\n", pStream->u8SD),
+    ASSERT_GUEST_LOGREL_MSG_RETURN(   pStreamR3->State.Mapping.cbFrameSize > 0
+                                   && u32CBL % pStreamR3->State.Mapping.cbFrameSize == 0,
+                                   ("CBL for stream #%RU8 does not align to frame size (u32CBL=%u cbFrameSize=%u)\n",
+                                    uSD, u32CBL, pStreamR3->State.Mapping.cbFrameSize),
                                    VERR_INVALID_PARAMETER);
 
@@ -258,12 +278,12 @@
     {
         if (Props.cChannels >= 5)
-            pStream->State.uTimerHz = 300;
+            pStreamShared->State.uTimerHz = 300;
         else if (Props.cChannels == 4)
-            pStream->State.uTimerHz = 150;
+            pStreamShared->State.uTimerHz = 150;
         else
-            pStream->State.uTimerHz = 100;
+            pStreamShared->State.uTimerHz = 100;
     }
     else
-        pStream->State.uTimerHz = pThis->uTimerHz;
+        pStreamShared->State.uTimerHz = pThis->uTimerHz;
 
 #ifndef VBOX_WITH_AUDIO_HDA_51_SURROUND
@@ -286,10 +306,10 @@
      * If not, we can skip a lot of the (re-)initialization and just (re-)use the existing stuff.
      * Also, tell the caller so that further actions can be taken. */
-    if (   uSD        == pStream->u8SD
-        && u64BDLBase == pStream->u64BDLBase
-        && u16LVI     == pStream->u16LVI
-        && u32CBL     == pStream->u32CBL
-        && u16FIFOS   == pStream->u16FIFOS
-        && u16FMT     == pStream->u16FMT)
+    if (   uSD        == pStreamShared->u8SD   /* paranoia OFC */
+        && u64BDLBase == pStreamShared->u64BDLBase
+        && u16LVI     == pStreamShared->u16LVI
+        && u32CBL     == pStreamShared->u32CBL
+        && u16FIFOS   == pStreamShared->u16FIFOS
+        && u16FMT     == pStreamShared->u16FMT)
     {
         LogFunc(("[SD%RU8] No format change, skipping (re-)initialization\n", uSD));
@@ -297,30 +317,30 @@
     }
 
-    pStream->u8SD       = uSD;
+    pStreamShared->u8SD       = uSD;
 
     /* Update all register copies so that we later know that something has changed. */
-    pStream->u64BDLBase = u64BDLBase;
-    pStream->u16LVI     = u16LVI;
-    pStream->u32CBL     = u32CBL;
-    pStream->u16FIFOS   = u16FIFOS;
-    pStream->u16FMT     = u16FMT;
-
-    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.Cfg;
+    pStreamShared->u64BDLBase = u64BDLBase;
+    pStreamShared->u16LVI     = u16LVI;
+    pStreamShared->u32CBL     = u32CBL;
+    pStreamShared->u16FIFOS   = u16FIFOS;
+    pStreamShared->u16FMT     = u16FMT;
+
+    PPDMAUDIOSTREAMCFG pCfg = &pStreamShared->State.Cfg;
     pCfg->Props = Props;
 
     /* (Re-)Allocate the stream's internal DMA buffer, based on the PCM  properties we just got above. */
-    if (pStream->State.pCircBuf)
-    {
-        RTCircBufDestroy(pStream->State.pCircBuf);
-        pStream->State.pCircBuf = NULL;
+    if (pStreamR3->State.pCircBuf)
+    {
+        RTCircBufDestroy(pStreamR3->State.pCircBuf);
+        pStreamR3->State.pCircBuf = NULL;
     }
 
     /* By default we allocate an internal buffer of 100ms. */
-    rc = RTCircBufCreate(&pStream->State.pCircBuf,
+    rc = RTCircBufCreate(&pStreamR3->State.pCircBuf,
                          DrvAudioHlpMilliToBytes(100 /* ms */, &pCfg->Props)); /** @todo Make this configurable. */
     AssertRCReturn(rc, rc);
 
     /* Set the stream's direction. */
-    pCfg->enmDir = hdaGetDirFromSD(pStream->u8SD);
+    pCfg->enmDir = hdaGetDirFromSD(uSD);
 
     /* The the stream's name, based on the direction. */
@@ -348,20 +368,20 @@
 
     /* Set scheduling hint (if available). */
-    if (pStream->State.uTimerHz)
-        pCfg->Device.cMsSchedulingHint = 1000 /* ms */ / pStream->State.uTimerHz;
+    if (pStreamShared->State.uTimerHz)
+        pCfg->Device.cMsSchedulingHint = 1000 /* ms */ / pStreamShared->State.uTimerHz;
 
     LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16\n",
-             pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS));
+             uSD, pStreamShared->u64BDLBase, pStreamShared->u32CBL, pStreamShared->u16LVI, pStreamShared->u16FIFOS));
 
     if (RT_SUCCESS(rc))
     {
         /* Make sure that the chosen Hz rate dividable by the stream's rate. */
-        if (pStream->State.Cfg.Props.uHz % pStream->State.uTimerHz != 0)
+        if (pStreamShared->State.Cfg.Props.uHz % pStreamShared->State.uTimerHz != 0)
             LogRel(("HDA: Stream timer Hz rate (%RU32) does not fit to stream #%RU8 timing (%RU32)\n",
-                    pStream->State.uTimerHz, pStream->u8SD, pStream->State.Cfg.Props.uHz));
+                    pStreamShared->State.uTimerHz, uSD, pStreamShared->State.Cfg.Props.uHz));
 
         /* Figure out how many transfer fragments we're going to use for this stream. */
         /** @todo Use a more dynamic fragment size? */
-        uint8_t cFragments = pStream->u16LVI + 1;
+        uint8_t cFragments = pStreamShared->u16LVI + 1;
         if (cFragments <= 1)
             cFragments = 2; /* At least two fragments (BDLEs) must be present. */
@@ -373,5 +393,5 @@
 
         LogFunc(("[SD%RU8] fPosAdjustEnabled=%RTbool, cPosAdjustFrames=%RU16\n",
-                 pStream->u8SD, pThis->fPosAdjustEnabled, pThis->cPosAdjustFrames));
+                 uSD, pThis->fPosAdjustEnabled, pThis->cPosAdjustFrames));
 
         if (pThis->fPosAdjustEnabled) /* Is the position adjustment enabled at all? */
@@ -380,5 +400,5 @@
             RT_ZERO(BDLE);
 
-            int rc2 = hdaR3BDLEFetch(pThis, &BDLE, pStream->u64BDLBase, 0 /* Entry */);
+            int rc2 = hdaR3BDLEFetch(pDevIns, &BDLE, pStreamShared->u64BDLBase, 0 /* Entry */);
             AssertRC(rc2);
 
@@ -400,10 +420,10 @@
 #ifdef VBOX_WITH_INTEL_HDA
                 /* Intel ICH / PCH: 1 frame. */
-                if (BDLE.Desc.u32BufSize == (uint32_t)(1 * pStream->State.Mapping.cbFrameSize))
+                if (BDLE.Desc.u32BufSize == (uint32_t)(1 * pStreamR3->State.Mapping.cbFrameSize))
                 {
                     cfPosAdjust = 1;
                 }
                 /* Intel Baytrail / Braswell: 32 frames. */
-                else if (BDLE.Desc.u32BufSize == (uint32_t)(32 * pStream->State.Mapping.cbFrameSize))
+                else if (BDLE.Desc.u32BufSize == (uint32_t)(32 * pStreamR3->State.Mapping.cbFrameSize))
                 {
                     cfPosAdjust = 32;
@@ -426,5 +446,5 @@
                  * position adjustment.
                  */
-                if (   (cfPosAdjust * pStream->State.Mapping.cbFrameSize) == BDLE.Desc.u32BufSize
+                if (   (cfPosAdjust * pStreamR3->State.Mapping.cbFrameSize) == BDLE.Desc.u32BufSize
                     && cFragments)
                 {
@@ -433,13 +453,13 @@
 
                 /* Initialize position adjustment counter. */
-                pStream->State.cfPosAdjustDefault = cfPosAdjust;
-                pStream->State.cfPosAdjustLeft    = pStream->State.cfPosAdjustDefault;
+                pStreamShared->State.cfPosAdjustDefault = cfPosAdjust;
+                pStreamShared->State.cfPosAdjustLeft    = pStreamShared->State.cfPosAdjustDefault;
 
                 LogRel2(("HDA: Position adjustment for stream #%RU8 active (%RU32 frames)\n",
-                         pStream->u8SD, pStream->State.cfPosAdjustDefault));
+                         uSD, pStreamShared->State.cfPosAdjustDefault));
             }
         }
 
-        LogFunc(("[SD%RU8] cfPosAdjust=%RU32, cFragments=%RU8\n", pStream->u8SD, cfPosAdjust, cFragments));
+        LogFunc(("[SD%RU8] cfPosAdjust=%RU32, cFragments=%RU8\n", uSD, cfPosAdjust, cFragments));
 
         /*
@@ -448,45 +468,45 @@
 
         /* Calculate the fragment size the guest OS expects interrupt delivery at. */
-        pStream->State.cbTransferSize = pStream->u32CBL / cFragments;
-        Assert(pStream->State.cbTransferSize);
-        Assert(pStream->State.cbTransferSize % pStream->State.Mapping.cbFrameSize == 0);
-        ASSERT_GUEST_LOGREL_MSG_STMT(pStream->State.cbTransferSize,
-                                     ("Transfer size for stream #%RU8 is invalid\n", pStream->u8SD), rc = VERR_INVALID_PARAMETER);
+        pStreamShared->State.cbTransferSize = pStreamShared->u32CBL / cFragments;
+        Assert(pStreamShared->State.cbTransferSize);
+        Assert(pStreamShared->State.cbTransferSize % pStreamR3->State.Mapping.cbFrameSize == 0);
+        ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize,
+                                     ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER);
         if (RT_SUCCESS(rc))
         {
             /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
              * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
-            pStream->State.cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz) * pStream->State.Mapping.cbFrameSize;
-            Assert(pStream->State.cbTransferChunk);
-            Assert(pStream->State.cbTransferChunk % pStream->State.Mapping.cbFrameSize == 0);
-            ASSERT_GUEST_LOGREL_MSG_STMT(pStream->State.cbTransferChunk,
-                                         ("Transfer chunk for stream #%RU8 is invalid\n", pStream->u8SD),
+            pStreamShared->State.cbTransferChunk = (pStreamShared->State.Cfg.Props.uHz / pStreamShared->State.uTimerHz) * pStreamR3->State.Mapping.cbFrameSize;
+            Assert(pStreamShared->State.cbTransferChunk);
+            Assert(pStreamShared->State.cbTransferChunk % pStreamR3->State.Mapping.cbFrameSize == 0);
+            ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk,
+                                         ("Transfer chunk for stream #%RU8 is invalid\n", uSD),
                                          rc = VERR_INVALID_PARAMETER);
             if (RT_SUCCESS(rc))
             {
                 /* Make sure that the transfer chunk does not exceed the overall transfer size. */
-                if (pStream->State.cbTransferChunk > pStream->State.cbTransferSize)
-                    pStream->State.cbTransferChunk = pStream->State.cbTransferSize;
-
-                const uint64_t cTicksPerHz = PDMDevHlpTimerGetFreq(pDevIns, pStream->hTimer) / pStream->State.uTimerHz;
+                if (pStreamShared->State.cbTransferChunk > pStreamShared->State.cbTransferSize)
+                    pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize;
+
+                const uint64_t cTicksPerHz = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer) / pStreamShared->State.uTimerHz;
 
                 /* Calculate the timer ticks per byte for this stream. */
-                pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk;
-                Assert(pStream->State.cTicksPerByte);
+                pStreamShared->State.cTicksPerByte = cTicksPerHz / pStreamShared->State.cbTransferChunk;
+                Assert(pStreamShared->State.cTicksPerByte);
 
                 /* Calculate timer ticks per transfer. */
-                pStream->State.cTransferTicks = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte;
-                Assert(pStream->State.cTransferTicks);
+                pStreamShared->State.cTransferTicks = pStreamShared->State.cbTransferChunk * pStreamShared->State.cTicksPerByte;
+                Assert(pStreamShared->State.cTransferTicks);
 
                 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, " \
                          "cTransferTicks=%RU64, cbTransferSize=%RU32\n",
-                         pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, pStream->State.cTicksPerByte,
-                         pStream->State.cbTransferChunk, pStream->State.cTransferTicks, pStream->State.cbTransferSize));
+                         uSD, pStreamShared->State.uTimerHz, cTicksPerHz, pStreamShared->State.cTicksPerByte,
+                         pStreamShared->State.cbTransferChunk, pStreamShared->State.cTransferTicks, pStreamShared->State.cbTransferSize));
 
                 /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
-                hdaR3StreamSetPosition(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
+                hdaR3StreamSetPosition(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
 
 #ifdef LOG_ENABLED
-                hdaR3BDLEDumpAll(pThis, pStream->u64BDLBase, pStream->u16LVI + 1);
+                hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
 #endif
             }
@@ -495,5 +515,5 @@
 
     if (RT_FAILURE(rc))
-        LogRel(("HDA: Initializing stream #%RU8 failed with %Rrc\n", pStream->u8SD, rc));
+        LogRel(("HDA: Initializing stream #%RU8 failed with %Rrc\n", uSD, rc));
 
     return rc;
@@ -503,17 +523,17 @@
  * Resets an HDA stream.
  *
- * @param   pThis               HDA state.
- * @param   pStream             HDA stream to reset.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
+ * @param   pStreamShared       HDA stream to reset (shared).
+ * @param   pStreamR3           HDA stream to reset (ring-3).
  * @param   uSD                 Stream descriptor (SD) number to use for this stream.
  */
-void hdaR3StreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD)
-{
-    AssertPtrReturnVoid(pThis);
-    AssertPtrReturnVoid(pStream);
-    AssertReturnVoid(uSD < HDA_MAX_STREAMS);
-
-# ifdef VBOX_STRICT
-    AssertReleaseMsg(!pStream->State.fRunning, ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
-# endif
+void hdaR3StreamReset(PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD)
+{
+    AssertPtr(pThis);
+    AssertPtr(pStreamShared);
+    AssertPtr(pStreamR3);
+    Assert(uSD < HDA_MAX_STREAMS);
+    AssertMsg(!pStreamShared->State.fRunning, ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
 
     LogFunc(("[SD%RU8] Reset\n", uSD));
@@ -522,6 +542,6 @@
      * Set reset state.
      */
-    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false); /* No nested calls. */
-    ASMAtomicXchgBool(&pStream->State.fInReset, true);
+    Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false); /* No nested calls. */
+    ASMAtomicXchgBool(&pStreamShared->State.fInReset, true);
 
     /*
@@ -548,36 +568,36 @@
 
     /* Assign the default mixer sink to the stream. */
-    pStream->pMixSink = hdaR3GetDefaultSink(pThis, uSD);
+    pStreamR3->pMixSink = hdaR3GetDefaultSink(pThisCC, uSD);
 
     /* Reset position adjustment counter. */
-    pStream->State.cfPosAdjustLeft = pStream->State.cfPosAdjustDefault;
+    pStreamShared->State.cfPosAdjustLeft = pStreamShared->State.cfPosAdjustDefault;
 
     /* Reset transfer stuff. */
-    pStream->State.cbTransferProcessed        = 0;
-    pStream->State.cTransferPendingInterrupts = 0;
-    pStream->State.tsTransferLast = 0;
-    pStream->State.tsTransferNext = 0;
+    pStreamShared->State.cbTransferProcessed        = 0;
+    pStreamShared->State.cTransferPendingInterrupts = 0;
+    pStreamShared->State.tsTransferLast = 0;
+    pStreamShared->State.tsTransferNext = 0;
 
     /* Initialize other timestamps. */
-    pStream->State.tsLastUpdateNs = 0;
-
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
-
-    if (pStream->State.pCircBuf)
-        RTCircBufReset(pStream->State.pCircBuf);
+    pStreamShared->State.tsLastUpdateNs = 0;
+
+    RT_ZERO(pStreamShared->State.BDLE);
+    pStreamShared->State.uCurBDLE = 0;
+
+    if (pStreamR3->State.pCircBuf)
+        RTCircBufReset(pStreamR3->State.pCircBuf);
 
     /* Reset the stream's period. */
-    hdaR3StreamPeriodReset(&pStream->State.Period);
+    hdaR3StreamPeriodReset(&pStreamShared->State.Period);
 
 #ifdef DEBUG
-    pStream->Dbg.cReadsTotal      = 0;
-    pStream->Dbg.cbReadTotal      = 0;
-    pStream->Dbg.tsLastReadNs     = 0;
-    pStream->Dbg.cWritesTotal     = 0;
-    pStream->Dbg.cbWrittenTotal   = 0;
-    pStream->Dbg.cWritesHz        = 0;
-    pStream->Dbg.cbWrittenHz      = 0;
-    pStream->Dbg.tsWriteSlotBegin = 0;
+    pStreamR3->Dbg.cReadsTotal      = 0;
+    pStreamR3->Dbg.cbReadTotal      = 0;
+    pStreamR3->Dbg.tsLastReadNs     = 0;
+    pStreamR3->Dbg.cWritesTotal     = 0;
+    pStreamR3->Dbg.cbWrittenTotal   = 0;
+    pStreamR3->Dbg.cWritesHz        = 0;
+    pStreamR3->Dbg.cbWrittenHz      = 0;
+    pStreamR3->Dbg.tsWriteSlotBegin = 0;
 #endif
 
@@ -588,5 +608,5 @@
 
     /* Exit reset mode. */
-    ASMAtomicXchgBool(&pStream->State.fInReset, false);
+    ASMAtomicXchgBool(&pStreamShared->State.fInReset, false);
 }
 
@@ -595,12 +615,14 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to enable or disable.
+ * @param   pStreamShared       HDA stream to enable or disable - shared bits.
+ * @param   pStreamR3           HDA stream to enable or disable - ring-3 bits.
  * @param   fEnable             Whether to enable or disble the stream.
  */
-int hdaR3StreamEnable(PHDASTREAM pStream, bool fEnable)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    LogFunc(("[SD%RU8] fEnable=%RTbool, pMixSink=%p\n", pStream->u8SD, fEnable, pStream->pMixSink));
+int hdaR3StreamEnable(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable)
+{
+    AssertPtr(pStreamR3);
+    AssertPtr(pStreamShared);
+
+    LogFunc(("[SD%RU8] fEnable=%RTbool, pMixSink=%p\n", pStreamShared->u8SD, fEnable, pStreamR3->pMixSink));
 
     int rc = VINF_SUCCESS;
@@ -610,34 +632,34 @@
 
     /* First, enable or disable the stream and the stream's sink, if any. */
-    if (   pStream->pMixSink
-        && pStream->pMixSink->pMixSink)
-        rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
+    if (   pStreamR3->pMixSink
+        && pStreamR3->pMixSink->pMixSink)
+        rc = AudioMixerSinkCtl(pStreamR3->pMixSink->pMixSink, enmCmd);
 
     if (   RT_SUCCESS(rc)
         && fEnable
-        && pStream->Dbg.Runtime.fEnabled)
-    {
-        Assert(DrvAudioHlpPCMPropsAreValid(&pStream->State.Cfg.Props));
+        && pStreamR3->Dbg.Runtime.fEnabled)
+    {
+        Assert(DrvAudioHlpPCMPropsAreValid(&pStreamShared->State.Cfg.Props));
 
         if (fEnable)
         {
-            if (!DrvAudioHlpFileIsOpen(pStream->Dbg.Runtime.pFileStream))
-            {
-                int rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileStream, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
-                                              &pStream->State.Cfg.Props);
+            if (!DrvAudioHlpFileIsOpen(pStreamR3->Dbg.Runtime.pFileStream))
+            {
+                int rc2 = DrvAudioHlpFileOpen(pStreamR3->Dbg.Runtime.pFileStream, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
+                                              &pStreamShared->State.Cfg.Props);
                 AssertRC(rc2);
             }
 
-            if (!DrvAudioHlpFileIsOpen(pStream->Dbg.Runtime.pFileDMARaw))
-            {
-                int rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileDMARaw, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
-                                              &pStream->State.Cfg.Props);
+            if (!DrvAudioHlpFileIsOpen(pStreamR3->Dbg.Runtime.pFileDMARaw))
+            {
+                int rc2 = DrvAudioHlpFileOpen(pStreamR3->Dbg.Runtime.pFileDMARaw, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
+                                              &pStreamShared->State.Cfg.Props);
                 AssertRC(rc2);
             }
 
-            if (!DrvAudioHlpFileIsOpen(pStream->Dbg.Runtime.pFileDMAMapped))
-            {
-                int rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileDMAMapped, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
-                                              &pStream->State.Cfg.Props);
+            if (!DrvAudioHlpFileIsOpen(pStreamR3->Dbg.Runtime.pFileDMAMapped))
+            {
+                int rc2 = DrvAudioHlpFileOpen(pStreamR3->Dbg.Runtime.pFileDMAMapped, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
+                                              &pStreamShared->State.Cfg.Props);
                 AssertRC(rc2);
             }
@@ -647,38 +669,39 @@
     if (RT_SUCCESS(rc))
     {
-        pStream->State.fRunning = fEnable;
-    }
-
-    LogFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8SD, rc));
+        pStreamShared->State.fRunning = fEnable;
+    }
+
+    LogFunc(("[SD%RU8] rc=%Rrc\n", pStreamShared->u8SD, rc));
     return rc;
 }
 
-uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStream)
-{
-    return HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-}
-
-/**
+static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared)
+{
+    return HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD);
+}
+
+/*
  * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
  * updating its associated LPIB register and DMA position buffer (if enabled).
  *
- * @param   pStream             HDA stream to update read / write position for.
+ * @param   pStreamShared       HDA stream to update read / write position for (shared).
+ * @param   pDevIns             The device instance.
+ * @param   pThis               The shared HDA device state.
  * @param   u32LPIB             Absolute position (in bytes) to set current read / write position to.
  */
-void hdaR3StreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB)
-{
-    AssertPtrReturnVoid(pStream);
-
-    Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
-              pStream->u8SD, u32LPIB, pStream->pHDAState->fDMAPosition));
+static void hdaR3StreamSetPosition(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB)
+{
+    AssertPtrReturnVoid(pStreamShared);
+
+    Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",  pStreamShared->u8SD, u32LPIB, pThis->fDMAPosition));
 
     /* Update LPIB in any case. */
-    HDA_STREAM_REG(pStream->pHDAState, LPIB, pStream->u8SD) = u32LPIB;
+    HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = u32LPIB;
 
     /* Do we need to tell the current DMA position? */
-    if (pStream->pHDAState->fDMAPosition)
-    {
-        int rc2 = PDMDevHlpPCIPhysWrite(pStream->pHDAState->CTX_SUFF(pDevIns),
-                                        pStream->pHDAState->u64DPBase + (pStream->u8SD * 2 * sizeof(uint32_t)),
+    if (pThis->fDMAPosition)
+    {
+        int rc2 = PDMDevHlpPCIPhysWrite(pDevIns,
+                                        pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)),
                                         (void *)&u32LPIB, sizeof(uint32_t));
         AssertRC(rc2);
@@ -690,14 +713,13 @@
  *
  * @returns Available data (in bytes).
- * @param   pStream             HDA stream to retrieve size for.
- */
-uint32_t hdaR3StreamGetUsed(PHDASTREAM pStream)
-{
-    AssertPtrReturn(pStream, 0);
-
-    if (!pStream->State.pCircBuf)
-        return 0;
-
-    return (uint32_t)RTCircBufUsed(pStream->State.pCircBuf);
+ * @param   pStreamR3           HDA stream to retrieve size for (ring-3).
+ */
+static uint32_t hdaR3StreamGetUsed(PHDASTREAMR3 pStreamR3)
+{
+    AssertPtrReturn(pStreamR3, 0);
+
+    if (pStreamR3->State.pCircBuf)
+        return (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
+    return 0;
 }
 
@@ -706,14 +728,13 @@
  *
  * @returns Free data (in bytes).
- * @param   pStream             HDA stream to retrieve size for.
- */
-uint32_t hdaR3StreamGetFree(PHDASTREAM pStream)
-{
-    AssertPtrReturn(pStream, 0);
-
-    if (!pStream->State.pCircBuf)
-        return 0;
-
-    return (uint32_t)RTCircBufFree(pStream->State.pCircBuf);
+ * @param   pStreamR3           HDA stream to retrieve size for (ring-3).
+ */
+static uint32_t hdaR3StreamGetFree(PHDASTREAMR3 pStreamR3)
+{
+    AssertPtrReturn(pStreamR3, 0);
+
+    if (pStreamR3->State.pCircBuf)
+        return (uint32_t)RTCircBufFree(pStreamR3->State.pCircBuf);
+    return 0;
 }
 
@@ -725,24 +746,22 @@
  *
  * @returns True if a next transfer is scheduled, false if not.
- * @param   pStream             HDA stream to retrieve schedule status for.
+ * @param   pStreamShared       HDA stream to retrieve schedule status for (shared).
  * @param   tsNow               The current time.
  */
-bool hdaR3StreamTransferIsScheduled(PHDASTREAM pStream, uint64_t tsNow)
-{
-    if (pStream)
-    {
-        AssertPtrReturn(pStream->pHDAState, false);
-
-        if (pStream->State.fRunning)
-        {
-            if (pStream->State.cTransferPendingInterrupts)
-            {
-                Log3Func(("[SD%RU8] Scheduled (%RU8 IRQs pending)\n", pStream->u8SD, pStream->State.cTransferPendingInterrupts));
+bool hdaR3StreamTransferIsScheduled(PHDASTREAM pStreamShared, uint64_t tsNow)
+{
+    if (pStreamShared)
+    {
+        if (pStreamShared->State.fRunning)
+        {
+            if (pStreamShared->State.cTransferPendingInterrupts)
+            {
+                Log3Func(("[SD%RU8] Scheduled (%RU8 IRQs pending)\n", pStreamShared->u8SD, pStreamShared->State.cTransferPendingInterrupts));
                 return true;
             }
 
-            if (pStream->State.tsTransferNext > tsNow)
-            {
-                Log3Func(("[SD%RU8] Scheduled in %RU64\n", pStream->u8SD, pStream->State.tsTransferNext - tsNow));
+            if (pStreamShared->State.tsTransferNext > tsNow)
+            {
+                Log3Func(("[SD%RU8] Scheduled in %RU64\n", pStreamShared->u8SD, pStreamShared->State.tsTransferNext - tsNow));
                 return true;
             }
@@ -757,9 +776,9 @@
  *
  * @returns The (virtual) clock timestamp of the next transfer.
- * @param   pStream             HDA stream to retrieve timestamp for.
- */
-uint64_t hdaR3StreamTransferGetNext(PHDASTREAM pStream)
-{
-    return pStream->State.tsTransferNext;
+ * @param   pStreamShared       HDA stream to retrieve timestamp for (shared).
+ */
+uint64_t hdaR3StreamTransferGetNext(PHDASTREAM pStreamShared)
+{
+    return pStreamShared->State.tsTransferNext;
 }
 
@@ -768,5 +787,5 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to write to.
+ * @param   pStreamR3           HDA stream to write to (ring-3).
  * @param   pvBuf               Data buffer to write.
  *                              If NULL, silence will be written.
@@ -774,15 +793,10 @@
  * @param   pcbWritten          Number of bytes written. Optional.
  */
-int hdaR3StreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pvBuf is optional. */
-    AssertReturn(cbBuf,      VERR_INVALID_PARAMETER);
-    /* pcbWritten is optional. */
-
-    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
+static int hdaR3StreamWrite(PHDASTREAMR3 pStreamR3, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+{
+    Assert(cbBuf);
+
+    PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;
     AssertPtr(pCircBuf);
-
-    int rc = VINF_SUCCESS;
 
     uint32_t cbWrittenTotal = 0;
@@ -793,5 +807,4 @@
         void *pvDst;
         size_t cbDst;
-
         RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, &pvDst, &cbDst);
 
@@ -799,7 +812,5 @@
         {
             if (pvBuf)
-            {
                 memcpy(pvDst, (uint8_t *)pvBuf + cbWrittenTotal, cbDst);
-            }
             else /* Send silence. */
             {
@@ -809,16 +820,14 @@
             }
 
-            if (pStream->Dbg.Runtime.fEnabled)
-                DrvAudioHlpFileWrite(pStream->Dbg.Runtime.pFileStream, pvDst, cbDst, 0 /* fFlags */);
+            if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
+            { /* likely */ }
+            else
+                DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileStream, pvDst, cbDst, 0 /* fFlags */);
         }
 
         RTCircBufReleaseWriteBlock(pCircBuf, cbDst);
-
-        if (RT_FAILURE(rc))
-            break;
 
         Assert(cbLeft  >= (uint32_t)cbDst);
         cbLeft         -= (uint32_t)cbDst;
-
         cbWrittenTotal += (uint32_t)cbDst;
     }
@@ -829,5 +838,5 @@
         *pcbWritten = cbWrittenTotal;
 
-    return rc;
+    return VINF_SUCCESS;
 }
 
@@ -837,25 +846,18 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to read audio data from.
+ * @param   pStreamR3           HDA stream to read audio data from (ring-3).
  * @param   cbToRead            Number of bytes to read.
  * @param   pcbRead             Number of bytes read. Optional.
  */
-int hdaR3StreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(cbToRead,   VERR_INVALID_PARAMETER);
-    /* pcbWritten is optional. */
-
-    PHDAMIXERSINK pSink = pStream->pMixSink;
-    if (!pSink)
-    {
-        AssertMsgFailed(("[SD%RU8] Can't read from a stream with no sink attached\n", pStream->u8SD));
-
-        if (pcbRead)
-            *pcbRead = 0;
-        return VINF_SUCCESS;
-    }
-
-    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
+static int hdaR3StreamRead(PHDASTREAMR3 pStreamR3, uint32_t cbToRead, uint32_t *pcbRead)
+{
+    Assert(cbToRead);
+
+    PHDAMIXERSINK pSink = pStreamR3->pMixSink;
+    AssertMsgReturnStmt(pSink, ("[SD%RU8] Can't read from a stream with no sink attached\n", pStreamR3->u8SD),
+                        if (pcbRead) *pcbRead = 0,
+                        VINF_SUCCESS);
+
+    PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;
     AssertPtr(pCircBuf);
 
@@ -876,6 +878,6 @@
         if (cbSrc)
         {
-            if (pStream->Dbg.Runtime.fEnabled)
-                DrvAudioHlpFileWrite(pStream->Dbg.Runtime.pFileStream, pvSrc, cbSrc, 0 /* fFlags */);
+            if (pStreamR3->Dbg.Runtime.fEnabled)
+                DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileStream, pvSrc, cbSrc, 0 /* fFlags */);
 
             rc = AudioMixerSinkWrite(pSink->pMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten);
@@ -883,5 +885,5 @@
 
             Assert(cbSrc >= cbWritten);
-            Log2Func(("[SD%RU8] %RU32/%zu bytes read\n", pStream->u8SD, cbWritten, cbSrc));
+            Log2Func(("[SD%RU8] %RU32/%zu bytes read\n", pStreamR3->u8SD, cbWritten, cbSrc));
         }
 
@@ -915,18 +917,18 @@
  * @returns IPRT status code.
  * @param   pDevIns             The device instance.
- * @param   pStream             HDA stream to update.
+ * @param   pThis               The shared HDA device state.
+ * @param   pThisCC             The ring-3 HDA device state.
+ * @param   pStreamShared       HDA stream to update (shared).
+ * @param   pStreamR3           HDA stream to update (ring-3).
  * @param   cbToProcessMax      How much data (in bytes) to process as maximum.
  * @param   fInTimer            Set if we're in the timer callout.
  */
-static int hdaR3StreamTransfer(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint32_t cbToProcessMax, bool fInTimer)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    hdaR3StreamLock(pStream);
-
-    PHDASTATE pThis = pStream->pHDAState;
-    AssertPtr(pThis);
-
-    PHDASTREAMPERIOD pPeriod = &pStream->State.Period;
+static int hdaR3StreamTransfer(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
+                               PHDASTREAMR3 pStreamR3, uint32_t cbToProcessMax, bool fInTimer)
+{
+    uint8_t const uSD = pStreamShared->u8SD;
+    hdaR3StreamLock(pStreamR3);
+
+    PHDASTREAMPERIOD pPeriod = &pStreamShared->State.Period;
     hdaR3StreamPeriodLock(pPeriod);
 
@@ -934,12 +936,12 @@
 
     /* Stream not running? */
-    if (!pStream->State.fRunning)
-    {
-        Log3Func(("[SD%RU8] Not running\n", pStream->u8SD));
+    if (!pStreamShared->State.fRunning)
+    {
+        Log3Func(("[SD%RU8] Not running\n", uSD));
         fProceed = false;
     }
-    else if (HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_SDSTS_BCIS)
-    {
-        Log3Func(("[SD%RU8] BCIS bit set\n", pStream->u8SD));
+    else if (HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS)
+    {
+        Log3Func(("[SD%RU8] BCIS bit set\n", uSD));
         fProceed = false;
     }
@@ -948,49 +950,48 @@
     {
         hdaR3StreamPeriodUnlock(pPeriod);
-        hdaR3StreamUnlock(pStream);
+        hdaR3StreamUnlock(pStreamR3);
         return VINF_SUCCESS;
     }
 
-    const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
-
-    if (!pStream->State.tsTransferLast)
-        pStream->State.tsTransferLast = tsNow;
+    const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
+
+    if (!pStreamShared->State.tsTransferLast)
+        pStreamShared->State.tsTransferLast = tsNow;
 
 #ifdef DEBUG
-    const int64_t iTimerDelta = tsNow - pStream->State.tsTransferLast;
+    const int64_t iTimerDelta = tsNow - pStreamShared->State.tsTransferLast;
     Log3Func(("[SD%RU8] Time now=%RU64, last=%RU64 -> %RI64 ticks delta\n",
-              pStream->u8SD, tsNow, pStream->State.tsTransferLast, iTimerDelta));
+              uSD, tsNow, pStreamShared->State.tsTransferLast, iTimerDelta));
 #endif
 
-    pStream->State.tsTransferLast = tsNow;
+    pStreamShared->State.tsTransferLast = tsNow;
 
     /* Sanity checks. */
-    Assert(pStream->u8SD < HDA_MAX_STREAMS);
-    Assert(pStream->u64BDLBase);
-    Assert(pStream->u32CBL);
-    Assert(pStream->u16FIFOS);
+    Assert(uSD < HDA_MAX_STREAMS);
+    Assert(pStreamShared->u64BDLBase);
+    Assert(pStreamShared->u32CBL);
+    Assert(pStreamShared->u16FIFOS);
 
     /* State sanity checks. */
-    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false);
+    Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false);
 
     int rc = VINF_SUCCESS;
 
     /* Fetch first / next BDL entry. */
-    PHDABDLE pBDLE = &pStream->State.BDLE;
+    PHDABDLE pBDLE = &pStreamShared->State.BDLE;
     if (hdaR3BDLEIsComplete(pBDLE))
     {
-        rc = hdaR3BDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+        rc = hdaR3BDLEFetch(pDevIns, pBDLE, pStreamShared->u64BDLBase, pStreamShared->State.uCurBDLE);
         AssertRC(rc);
     }
 
-    uint32_t cbToProcess = RT_MIN(pStream->State.cbTransferSize - pStream->State.cbTransferProcessed,
-                                  pStream->State.cbTransferChunk);
-
-    Log3Func(("[SD%RU8] cbToProcess=%RU32, cbToProcessMax=%RU32\n", pStream->u8SD, cbToProcess, cbToProcessMax));
+    uint32_t cbToProcess = RT_MIN(pStreamShared->State.cbTransferSize - pStreamShared->State.cbTransferProcessed,
+                                  pStreamShared->State.cbTransferChunk);
+
+    Log3Func(("[SD%RU8] cbToProcess=%RU32, cbToProcessMax=%RU32\n", uSD, cbToProcess, cbToProcessMax));
 
     if (cbToProcess > cbToProcessMax)
     {
-        LogFunc(("[SD%RU8] Limiting transfer (cbToProcess=%RU32, cbToProcessMax=%RU32)\n",
-                 pStream->u8SD, cbToProcess, cbToProcessMax));
+        LogFunc(("[SD%RU8] Limiting transfer (cbToProcess=%RU32, cbToProcessMax=%RU32)\n", uSD, cbToProcess, cbToProcessMax));
 
         /* Never process more than a stream currently can handle. */
@@ -1005,5 +1006,5 @@
     {
         /* Limit the chunk to the stream's FIFO size and what's left to process. */
-        uint32_t cbChunk = RT_MIN(cbLeft, pStream->u16FIFOS);
+        uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u16FIFOS);
 
         /* Limit the chunk to the remaining data of the current BDLE. */
@@ -1012,9 +1013,9 @@
         /* If there are position adjustment frames left to be processed,
          * make sure that we process them first as a whole. */
-        if (pStream->State.cfPosAdjustLeft)
-            cbChunk = RT_MIN(cbChunk, uint32_t(pStream->State.cfPosAdjustLeft * pStream->State.Mapping.cbFrameSize));
+        if (pStreamShared->State.cfPosAdjustLeft)
+            cbChunk = RT_MIN(cbChunk, uint32_t(pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize));
 
         Log3Func(("[SD%RU8] cbChunk=%RU32, cPosAdjustFramesLeft=%RU16\n",
-                  pStream->u8SD, cbChunk, pStream->State.cfPosAdjustLeft));
+                  uSD, cbChunk, pStreamShared->State.cfPosAdjustLeft));
 
         if (!cbChunk)
@@ -1022,7 +1023,7 @@
 
         uint32_t   cbDMA    = 0;
-        PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
-
-        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) /* Input (SDI). */
+        PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf;
+
+        if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN) /* Input (SDI). */
         {
             STAM_PROFILE_START(&pThis->StatIn, a);
@@ -1054,5 +1055,5 @@
             if (cbDMAToWrite)
             {
-                LogRel2(("HDA: FIFO underflow for stream #%RU8 (%RU32 bytes outstanding)\n", pStream->u8SD, cbDMAToWrite));
+                LogRel2(("HDA: FIFO underflow for stream #%RU8 (%RU32 bytes outstanding)\n", uSD, cbDMAToWrite));
 
                 Assert(cbChunk == cbDMAWritten + cbDMAToWrite);
@@ -1061,15 +1062,15 @@
             }
 
-            rc = hdaR3DMAWrite(pThis, pStream, abChunk, cbDMAWritten, &cbDMA /* pcbWritten */);
+            rc = hdaR3DMAWrite(pDevIns, pThis, pStreamShared, pStreamR3, abChunk, cbDMAWritten, &cbDMA /* pcbWritten */);
             if (RT_FAILURE(rc))
-                LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
+                LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", uSD, rc));
 
             STAM_PROFILE_STOP(&pThis->StatIn, a);
         }
-        else if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
+        else if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT) /* Output (SDO). */
         {
             STAM_PROFILE_START(&pThis->StatOut, a);
 
-            rc = hdaR3DMARead(pThis, pStream, abChunk, cbChunk, &cbDMA /* pcbRead */);
+            rc = hdaR3DMARead(pDevIns, pThis, pStreamShared, pStreamR3, abChunk, cbChunk, &cbDMA /* pcbRead */);
             if (RT_SUCCESS(rc))
             {
@@ -1083,5 +1084,5 @@
                  * Only macOS guests need the frame extraction branch below at the moment AFAIK.
                  */
-                if (pStream->State.Mapping.cbFrameSize == HDA_FRAME_SIZE_DEFAULT)
+                if (pStreamR3->State.Mapping.cbFrameSize == HDA_FRAME_SIZE_DEFAULT)
                 {
                     uint32_t cbDMARead = 0;
@@ -1119,11 +1120,11 @@
                      */
                     /** @todo Optimize channel data extraction! Use some SSE(3) / intrinsics? */
-                    for (unsigned m = 0; m < pStream->State.Mapping.cMappings; m++)
+                    for (unsigned m = 0; m < pStreamR3->State.Mapping.cMappings; m++)
                     {
-                        const uint32_t cbFrame  = pStream->State.Mapping.cbFrameSize;
+                        const uint32_t cbFrame  = pStreamR3->State.Mapping.cbFrameSize;
 
                         Assert(cbFree >= cbDMA);
 
-                        PPDMAUDIOSTREAMMAP pMap = &pStream->State.Mapping.paMappings[m];
+                        PPDMAUDIOSTREAMMAP pMap = &pStreamR3->State.Mapping.paMappings[m];
                         AssertPtr(pMap);
 
@@ -1150,6 +1151,6 @@
 
 #if 0 /* Too slow, even for release builds, so disabled it. */
-                                if (pStream->Dbg.Runtime.fEnabled)
-                                    DrvAudioHlpFileWrite(pStream->Dbg.Runtime.pFileDMAMapped, pvDstBuf, cbDstBuf,
+                                if (pStreamR3->Dbg.Runtime.fEnabled)
+                                    DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMAMapped, pvDstBuf, cbDstBuf,
                                                          0 /* fFlags */);
 #endif
@@ -1200,5 +1201,5 @@
             }
             else
-                LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
+                LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", uSD, rc));
 
             STAM_PROFILE_STOP(&pThis->StatOut, a);
@@ -1217,5 +1218,5 @@
             /* Are we done doing the position adjustment?
              * Only then do the transfer accounting .*/
-            if (pStream->State.cfPosAdjustLeft == 0)
+            if (pStreamShared->State.cfPosAdjustLeft == 0)
             {
                 Assert(cbLeft >= cbDMA);
@@ -1230,14 +1231,14 @@
              * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
              */
-            uint32_t cbStreamPos = hdaR3StreamGetPosition(pThis, pStream);
-            if (cbStreamPos == pStream->u32CBL)
+            uint32_t cbStreamPos = hdaR3StreamGetPosition(pThis, pStreamShared);
+            if (cbStreamPos == pStreamShared->u32CBL)
                 cbStreamPos = 0;
 
-            hdaR3StreamSetPosition(pStream, cbStreamPos + cbDMA);
+            hdaR3StreamSetPosition(pStreamShared, pDevIns, pThis, cbStreamPos + cbDMA);
         }
 
         if (hdaR3BDLEIsComplete(pBDLE))
         {
-            Log3Func(("[SD%RU8] Complete: %R[bdle]\n", pStream->u8SD, pBDLE));
+            Log3Func(("[SD%RU8] Complete: %R[bdle]\n", uSD, pBDLE));
 
                 /* Does the current BDLE require an interrupt to be sent? */
@@ -1248,33 +1249,33 @@
                  *
                  * In such a case we need to skip such an interrupt and just move on. */
-                && pStream->State.cfPosAdjustLeft == 0)
+                && pStreamShared->State.cfPosAdjustLeft == 0)
             {
                 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set
                  * we need to generate an interrupt.
                  */
-                if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_IOCE)
+                if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE)
                 {
-                    pStream->State.cTransferPendingInterrupts++;
-
-                    AssertMsg(pStream->State.cTransferPendingInterrupts <= 32,
+                    pStreamShared->State.cTransferPendingInterrupts++;
+
+                    AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32,
                               ("Too many pending interrupts (%RU8) for stream #%RU8\n",
-                               pStream->State.cTransferPendingInterrupts, pStream->u8SD));
+                               pStreamShared->State.cTransferPendingInterrupts, uSD));
                 }
             }
 
-            if (pStream->State.uCurBDLE == pStream->u16LVI)
-            {
-                pStream->State.uCurBDLE = 0;
+            if (pStreamShared->State.uCurBDLE == pStreamShared->u16LVI)
+            {
+                pStreamShared->State.uCurBDLE = 0;
             }
             else
-                pStream->State.uCurBDLE++;
+                pStreamShared->State.uCurBDLE++;
 
             /* Fetch the next BDLE entry. */
-            hdaR3BDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+            hdaR3BDLEFetch(pDevIns, pBDLE, pStreamShared->u64BDLBase, pStreamShared->State.uCurBDLE);
         }
 
         /* Do the position adjustment accounting. */
-        pStream->State.cfPosAdjustLeft -=
-            RT_MIN(pStream->State.cfPosAdjustLeft, cbDMA / pStream->State.Mapping.cbFrameSize);
+        pStreamShared->State.cfPosAdjustLeft -=
+            RT_MIN(pStreamShared->State.cfPosAdjustLeft, cbDMA / pStreamR3->State.Mapping.cbFrameSize);
 
         if (RT_FAILURE(rc))
@@ -1283,5 +1284,5 @@
 
     Log3Func(("[SD%RU8] cbToProcess=%RU32, cbProcessed=%RU32, cbLeft=%RU32, %R[bdle], rc=%Rrc\n",
-              pStream->u8SD, cbToProcess, cbProcessed, cbLeft, pBDLE, rc));
+              uSD, cbToProcess, cbProcessed, cbLeft, pBDLE, rc));
 
     /* Sanity. */
@@ -1291,17 +1292,17 @@
     /* Only do the data accounting if we don't have to do any position
      * adjustment anymore. */
-    if (pStream->State.cfPosAdjustLeft == 0)
-    {
-        hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStream->State.Mapping.cbFrameSize,
+    if (pStreamShared->State.cfPosAdjustLeft == 0)
+    {
+        hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbFrameSize,
                                              hdaR3StreamPeriodGetRemainingFrames(pPeriod)));
 
-        pStream->State.cbTransferProcessed += cbProcessed;
+        pStreamShared->State.cbTransferProcessed += cbProcessed;
     }
 
     /* Make sure that we never report more stuff processed than initially announced. */
-    if (pStream->State.cbTransferProcessed > pStream->State.cbTransferSize)
-        pStream->State.cbTransferProcessed = pStream->State.cbTransferSize;
-
-    uint32_t cbTransferLeft     = pStream->State.cbTransferSize - pStream->State.cbTransferProcessed;
+    if (pStreamShared->State.cbTransferProcessed > pStreamShared->State.cbTransferSize)
+        pStreamShared->State.cbTransferProcessed = pStreamShared->State.cbTransferSize;
+
+    uint32_t cbTransferLeft     = pStreamShared->State.cbTransferSize - pStreamShared->State.cbTransferProcessed;
     bool     fTransferComplete  = !cbTransferLeft;
     uint64_t tsTransferNext     = 0;
@@ -1321,9 +1322,9 @@
          *         sound output. Running VLC on the guest will tell!
          */
-        const bool fWalClkSet = hdaR3WalClkSet(pThis,
+        const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC,
                                                  hdaWalClkGetCurrent(pThis)
                                                + hdaR3StreamPeriodFramesToWalClk(pPeriod,
-                                                                                   pStream->State.cbTransferProcessed
-                                                                                 / pStream->State.Mapping.cbFrameSize),
+                                                                                   pStreamShared->State.cbTransferProcessed
+                                                                                 / pStreamR3->State.Mapping.cbFrameSize),
                                                false /* fForce */);
         RT_NOREF(fWalClkSet);
@@ -1331,7 +1332,7 @@
 
     /* Does the period have any interrupts outstanding? */
-    if (pStream->State.cTransferPendingInterrupts)
-    {
-        Log3Func(("[SD%RU8] Scheduling interrupt\n", pStream->u8SD));
+    if (pStreamShared->State.cTransferPendingInterrupts)
+    {
+        Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD));
 
         /*
@@ -1346,9 +1347,9 @@
          * snd_hda_intel on Linux will tell.
          */
-        HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_SDSTS_BCIS;
+        HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS;
 
         /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
          * ending / beginning a period. */
-        HDA_PROCESS_INTERRUPT(pThis->pDevInsR3, pThis);
+        HDA_PROCESS_INTERRUPT(pDevIns, pThis);
     }
     else /* Transfer still in-flight -- schedule the next timing slot. */
@@ -1359,10 +1360,10 @@
          * than we can transfer per timing slot? Clamp. */
         if (   !cbTransferNext
-            || cbTransferNext > pStream->State.cbTransferChunk)
-        {
-            cbTransferNext = pStream->State.cbTransferChunk;
+            || cbTransferNext > pStreamShared->State.cbTransferChunk)
+        {
+            cbTransferNext = pStreamShared->State.cbTransferChunk;
         }
 
-        tsTransferNext = tsNow + (cbTransferNext * pStream->State.cTicksPerByte);
+        tsTransferNext = tsNow + (cbTransferNext * pStreamShared->State.cTicksPerByte);
 
         /*
@@ -1374,5 +1375,5 @@
          */
         if (fTransferComplete)
-            pStream->State.cbTransferProcessed = 0;
+            pStreamShared->State.cbTransferProcessed = 0;
     }
 
@@ -1380,24 +1381,25 @@
     if (tsTransferNext) /* Can be 0 if no next transfer is needed. */
     {
-        Log3Func(("[SD%RU8] Scheduling timer\n", pStream->u8SD));
-
-        LogFunc(("Timer set SD%RU8\n", pStream->u8SD));
-        Assert(!fInTimer || tsNow == PDMDevHlpTimerGet(pDevIns, pStream->hTimer));
-        hdaR3TimerSet(pDevIns, pStream, tsTransferNext, true /* fForce - skip tsTransferNext check */, fInTimer ? tsNow : 0);
-
-        pStream->State.tsTransferNext = tsTransferNext;
-    }
-
-    pStream->State.tsTransferLast = tsNow;
+        Log3Func(("[SD%RU8] Scheduling timer\n", uSD));
+
+        LogFunc(("Timer set SD%RU8\n", uSD));
+        Assert(!fInTimer || tsNow == PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer));
+        hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext,
+                      true /* fForce - skip tsTransferNext check */, fInTimer ? tsNow : 0);
+
+        pStreamShared->State.tsTransferNext = tsTransferNext;
+    }
+
+    pStreamShared->State.tsTransferLast = tsNow;
 
     Log3Func(("[SD%RU8] cbTransferLeft=%RU32 -- %RU32/%RU32\n",
-              pStream->u8SD, cbTransferLeft, pStream->State.cbTransferProcessed, pStream->State.cbTransferSize));
+              uSD, cbTransferLeft, pStreamShared->State.cbTransferProcessed, pStreamShared->State.cbTransferSize));
     Log3Func(("[SD%RU8] fTransferComplete=%RTbool, cTransferPendingInterrupts=%RU8\n",
-              pStream->u8SD, fTransferComplete, pStream->State.cTransferPendingInterrupts));
+              uSD, fTransferComplete, pStreamShared->State.cTransferPendingInterrupts));
     Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferNext=%RU64 (in %RU64 ticks)\n",
-              pStream->u8SD, tsNow, tsTransferNext, tsTransferNext - tsNow));
+              uSD, tsNow, tsTransferNext, tsTransferNext - tsNow));
 
     hdaR3StreamPeriodUnlock(pPeriod);
-    hdaR3StreamUnlock(pStream);
+    hdaR3StreamUnlock(pStreamR3);
 
     return VINF_SUCCESS;
@@ -1421,20 +1423,21 @@
  * (with fInTimer set to @c false).
  *
- * @param   pDevIns     The device instance.
- * @param   pStream     HDA stream to update.
- * @param   fInTimer    Whether to this function was called from the timer
- *                      context or an asynchronous I/O stream thread (if supported).
- */
-void hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTREAM pStream, bool fInTimer)
-{
-    if (!pStream)
+ * @param   pDevIns         The device instance.
+ * @param   pThis           The shared HDA device state.
+ * @param   pThisCC         The ring-3 HDA device state.
+ * @param   pStreamShared   HDA stream to update (shared bits).
+ * @param   pStreamR3       HDA stream to update (ring-3 bits).
+ * @param   fInTimer        Whether to this function was called from the timer
+ *                          context or an asynchronous I/O stream thread (if supported).
+ */
+void hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
+                       PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer)
+{
+    if (!pStreamShared)
         return;
 
     PAUDMIXSINK pSink = NULL;
-    if (   pStream->pMixSink
-        && pStream->pMixSink->pMixSink)
-    {
-        pSink = pStream->pMixSink->pMixSink;
-    }
+    if (pStreamR3->pMixSink)
+        pSink = pStreamR3->pMixSink->pMixSink;
 
     if (!AudioMixerSinkIsActive(pSink)) /* No sink available? Bail out. */
@@ -1443,5 +1446,5 @@
     int rc2;
 
-    if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
+    if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
     {
         bool fDoRead = false; /* Whether to read from the HDA stream or not. */
@@ -1451,9 +1454,9 @@
 # endif
         {
-            const uint32_t cbStreamFree = hdaR3StreamGetFree(pStream);
+            const uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
             if (cbStreamFree)
             {
                 /* Do the DMA transfer. */
-                rc2 = hdaR3StreamTransfer(pDevIns, pStream, cbStreamFree, fInTimer);
+                rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree, fInTimer);
                 AssertRC(rc2);
             }
@@ -1461,17 +1464,17 @@
             /* Only read from the HDA stream at the given scheduling rate. */
             const uint64_t tsNowNs = RTTimeNanoTS();
-            if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
+            if (tsNowNs - pStreamShared->State.tsLastUpdateNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
             {
                 fDoRead = true;
-                pStream->State.tsLastUpdateNs = tsNowNs;
+                pStreamShared->State.tsLastUpdateNs = tsNowNs;
             }
         }
 
-        Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStream->u8SD, fInTimer, fDoRead));
+        Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStreamShared->u8SD, fInTimer, fDoRead));
 
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
         if (fDoRead)
         {
-            rc2 = hdaR3StreamAsyncIONotify(pStream);
+            rc2 = hdaR3StreamAsyncIONotify(pStreamR3);
             AssertRC(rc2);
         }
@@ -1486,13 +1489,13 @@
 # endif
             const uint32_t cbSinkWritable     = AudioMixerSinkGetWritable(pSink);
-            const uint32_t cbStreamReadable   = hdaR3StreamGetUsed(pStream);
+            const uint32_t cbStreamReadable   = hdaR3StreamGetUsed(pStreamR3);
             const uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
 
-            Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStream->u8SD, cbSinkWritable, cbStreamReadable));
+            Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStreamShared->u8SD, cbSinkWritable, cbStreamReadable));
 
             if (cbToReadFromStream)
             {
                 /* Read (guest output) data and write it to the stream's sink. */
-                rc2 = hdaR3StreamRead(pStream, cbToReadFromStream, NULL /* pcbRead */);
+                rc2 = hdaR3StreamRead(pStreamR3, cbToReadFromStream, NULL /* pcbRead */);
                 AssertRC(rc2);
             }
@@ -1517,7 +1520,7 @@
 
             /* How much (guest input) data is available for writing at the moment for the HDA stream? */
-            const uint32_t cbStreamFree = hdaR3StreamGetFree(pStream);
-
-            Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStream->u8SD, cbSinkReadable, cbStreamFree));
+            const uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
+
+            Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStreamShared->u8SD, cbSinkReadable, cbStreamFree));
 
             /* Do not read more than the HDA stream can hold at the moment.
@@ -1544,12 +1547,7 @@
                     /* Write (guest input) data to the stream which was read from stream's sink before. */
                     uint32_t cbWritten;
-                    rc2 = hdaR3StreamWrite(pStream, abFIFO, cbRead, &cbWritten);
+                    rc2 = hdaR3StreamWrite(pStreamR3, abFIFO, cbRead, &cbWritten);
                     AssertRCBreak(rc2);
-
-                    if (!cbWritten)
-                    {
-                        AssertFailed(); /* Should never happen, as we know how much we can write. */
-                        break;
-                    }
+                    AssertBreak(cbWritten > 0); /* Should never happen, as we know how much we can write. */
 
                     Assert(cbSinkReadable >= cbRead);
@@ -1565,16 +1563,16 @@
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
             const uint64_t tsNowNs = RTTimeNanoTS();
-            if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
-            {
-                rc2 = hdaR3StreamAsyncIONotify(pStream);
+            if (tsNowNs - pStreamShared->State.tsLastUpdateNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
+            {
+                rc2 = hdaR3StreamAsyncIONotify(pStreamR3);
                 AssertRC(rc2);
 
-                pStream->State.tsLastUpdateNs = tsNowNs;
+                pStreamShared->State.tsLastUpdateNs = tsNowNs;
             }
 # endif
-            const uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStream);
+            const uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
             if (cbStreamUsed)
             {
-                rc2 = hdaR3StreamTransfer(pDevIns, pStream, cbStreamUsed, fInTimer);
+                rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamUsed, fInTimer);
                 AssertRC(rc2);
             }
@@ -1589,11 +1587,11 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to lock.
- */
-void hdaR3StreamLock(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
+ * @param   pStreamR3           HDA stream to lock (ring-3 bits).
+ */
+void hdaR3StreamLock(PHDASTREAMR3 pStreamR3)
+{
+    AssertPtrReturnVoid(pStreamR3);
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    int rc2 = RTCritSectEnter(&pStream->CritSect);
+    int rc2 = RTCritSectEnter(&pStreamR3->CritSect);
     AssertRC(rc2);
 # else
@@ -1606,15 +1604,16 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to unlock.
- */
-void hdaR3StreamUnlock(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
+ * @param   pStreamR3           HDA stream to unlock (ring-3 bits).
+ */
+void hdaR3StreamUnlock(PHDASTREAMR3 pStreamR3)
+{
+    AssertPtrReturnVoid(pStreamR3);
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    int rc2 = RTCritSectLeave(&pStream->CritSect);
+    int rc2 = RTCritSectLeave(&pStreamR3->CritSect);
     AssertRC(rc2);
 # endif
 }
 
+#if 0 /* unused - no prototype even */
 /**
  * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
@@ -1622,29 +1621,26 @@
  *
  * @returns Set LPIB value.
+ * @param   pDevIns             The device instance.
  * @param   pStream             HDA stream to update read / write position for.
  * @param   u32LPIB             New LPIB (position) value to set.
  */
-uint32_t hdaR3StreamUpdateLPIB(PHDASTREAM pStream, uint32_t u32LPIB)
-{
-    AssertPtrReturn(pStream, 0);
-
-    AssertMsg(u32LPIB <= pStream->u32CBL,
-              ("[SD%RU8] New LPIB (%RU32) exceeds CBL (%RU32)\n", pStream->u8SD, u32LPIB, pStream->u32CBL));
-
-    const PHDASTATE pThis = pStream->pHDAState;
-
-    u32LPIB = RT_MIN(u32LPIB, pStream->u32CBL);
+uint32_t hdaR3StreamUpdateLPIB(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint32_t u32LPIB)
+{
+    AssertMsg(u32LPIB <= pStreamShared->u32CBL,
+              ("[SD%RU8] New LPIB (%RU32) exceeds CBL (%RU32)\n", pStreamShared->u8SD, u32LPIB, pStreamShared->u32CBL));
+
+    u32LPIB = RT_MIN(u32LPIB, pStreamShared->u32CBL);
 
     LogFlowFunc(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
-                 pStream->u8SD, u32LPIB, pThis->fDMAPosition));
+                 pStreamShared->u8SD, u32LPIB, pThis->fDMAPosition));
 
     /* Update LPIB in any case. */
-    HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) = u32LPIB;
+    HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = u32LPIB;
 
     /* Do we need to tell the current DMA position? */
     if (pThis->fDMAPosition)
     {
-        int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
-                                        pThis->u64DPBase + (pStream->u8SD * 2 * sizeof(uint32_t)),
+        int rc2 = PDMDevHlpPCIPhysWrite(pDevIns,
+                                        pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)),
                                         (void *)&u32LPIB, sizeof(uint32_t));
         AssertRC(rc2);
@@ -1653,4 +1649,5 @@
     return u32LPIB;
 }
+#endif
 
 # ifdef HDA_USE_DMA_ACCESS_HANDLER
@@ -1664,6 +1661,6 @@
 {
     /* At least LVI and the BDL base must be set. */
-    if (   !pStream->u16LVI
-        || !pStream->u64BDLBase)
+    if (   !pStreamShared->u16LVI
+        || !pStreamShared->u64BDLBase)
     {
         return false;
@@ -1688,8 +1685,8 @@
     size_t cRanges = 0;
 
-    for (uint16_t i = 0; i < pStream->u16LVI + 1; i++)
+    for (uint16_t i = 0; i < pStreamShared->u16LVI + 1; i++)
     {
         HDABDLE BDLE;
-        rc = hdaR3BDLEFetch(pThis, &BDLE, pStream->u64BDLBase, i /* Index */);
+        rc = hdaR3BDLEFetch(pDevIns, &BDLE, pStreamShared->u64BDLBase, i /* Index */);
         if (RT_FAILURE(rc))
             break;
@@ -1827,31 +1824,30 @@
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
 /**
+ * @callback_method_impl{FNRTTHREAD,
  * Asynchronous I/O thread for a HDA stream.
- * This will do the heavy lifting work for us as soon as it's getting notified by another thread.
- *
- * @returns IPRT status code.
- * @param   hThreadSelf         Thread handle.
- * @param   pvUser              User argument. Must be of type PHDASTREAMTHREADCTX.
- */
-DECLCALLBACK(int) hdaR3StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
-{
-    PHDASTREAMTHREADCTX pCtx = (PHDASTREAMTHREADCTX)pvUser;
-    AssertPtr(pCtx);
-    PHDASTREAM pStream = pCtx->pStream;
-
-    AssertPtr(pStream);
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
-
-    PPDMDEVINS pDevIns = pCtx->pThis->pDevInsR3;
-
+ *
+ * This will do the heavy lifting work for us as soon as it's getting notified
+ * by another thread.}
+ */
+static DECLCALLBACK(int) hdaR3StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
+{
+    PHDASTREAMR3 const       pStreamR3     = (PHDASTREAMR3)pvUser;
+    PHDASTREAMSTATEAIO const pAIO          = &pStreamR3->State.AIO;
+    PHDASTATE const          pThis         = pStreamR3->pHDAStateShared;
+    PHDASTATER3 const        pThisCC       = pStreamR3->pHDAStateR3;
+    PPDMDEVINS const         pDevIns       = pThisCC->pDevIns;
+    PHDASTREAM const         pStreamShared = &pThis->aStreams[pStreamR3 - &pThisCC->aStreams[0]];
+    Assert(pStreamR3 - &pThisCC->aStreams[0] == pStreamR3->u8SD);
+    Assert(pStreamShared->u8SD == pStreamR3->u8SD);
+
+    /* Signal parent thread that we've started  */
     ASMAtomicXchgBool(&pAIO->fStarted, true);
-
     RTThreadUserSignal(hThreadSelf);
 
-    LogFunc(("[SD%RU8] Started\n", pStream->u8SD));
+    LogFunc(("[SD%RU8] Started\n", pStreamShared->u8SD));
 
     for (;;)
     {
-        int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT);
+        int rc2 = RTSemEventWait(pAIO->hEvent, RT_INDEFINITE_WAIT);
         if (RT_FAILURE(rc2))
             break;
@@ -1861,4 +1857,5 @@
 
         rc2 = RTCritSectEnter(&pAIO->CritSect);
+        AssertRC(rc2);
         if (RT_SUCCESS(rc2))
         {
@@ -1869,15 +1866,12 @@
             }
 
-            hdaR3StreamUpdate(pDevIns, pStream, false /* fInTimer */);
+            hdaR3StreamUpdate(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, false /* fInTimer */);
 
             int rc3 = RTCritSectLeave(&pAIO->CritSect);
             AssertRC(rc3);
         }
-
-        AssertRC(rc2);
-    }
-
-    LogFunc(("[SD%RU8] Ended\n", pStream->u8SD));
-
+    }
+
+    LogFunc(("[SD%RU8] Ended\n", pStreamShared->u8SD));
     ASMAtomicXchgBool(&pAIO->fStarted, false);
 
@@ -1889,9 +1883,9 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA audio stream to create the async I/O thread for.
- */
-int hdaR3StreamAsyncIOCreate(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+ * @param   pStreamR3           HDA audio stream to create the async I/O thread for.
+ */
+int hdaR3StreamAsyncIOCreate(PHDASTREAMR3 pStreamR3)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStreamR3->State.AIO;
 
     int rc;
@@ -1902,5 +1896,5 @@
         pAIO->fEnabled  = true; /* Enabled by default. */
 
-        rc = RTSemEventCreate(&pAIO->Event);
+        rc = RTSemEventCreate(&pAIO->hEvent);
         if (RT_SUCCESS(rc))
         {
@@ -1908,13 +1902,8 @@
             if (RT_SUCCESS(rc))
             {
-                HDASTREAMTHREADCTX Ctx = { pStream->pHDAState, pStream };
-
-                char szThreadName[64];
-                RTStrPrintf2(szThreadName, sizeof(szThreadName), "hdaAIO%RU8", pStream->u8SD);
-
-                rc = RTThreadCreate(&pAIO->Thread, hdaR3StreamAsyncIOThread, &Ctx,
-                                    0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, szThreadName);
+                rc = RTThreadCreateF(&pAIO->hThread, hdaR3StreamAsyncIOThread, pStreamR3, 0 /*cbStack*/,
+                                     RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "hdaAIO%RU8", pStreamR3->u8SD);
                 if (RT_SUCCESS(rc))
-                    rc = RTThreadUserWait(pAIO->Thread, 10 * 1000 /* 10s timeout */);
+                    rc = RTThreadUserWait(pAIO->hThread, 10 * 1000 /* 10s timeout */);
             }
         }
@@ -1923,5 +1912,5 @@
         rc = VINF_SUCCESS;
 
-    LogFunc(("[SD%RU8] Returning %Rrc\n", pStream->u8SD, rc));
+    LogFunc(("[SD%RU8] Returning %Rrc\n", pStreamR3->u8SD, rc));
     return rc;
 }
@@ -1931,9 +1920,9 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA audio stream to destroy the async I/O thread for.
- */
-int hdaR3StreamAsyncIODestroy(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+ * @param   pStreamR3           HDA audio stream to destroy the async I/O thread for.
+ */
+static int hdaR3StreamAsyncIODestroy(PHDASTREAMR3 pStreamR3)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStreamR3->State.AIO;
 
     if (!ASMAtomicReadBool(&pAIO->fStarted))
@@ -1942,18 +1931,21 @@
     ASMAtomicWriteBool(&pAIO->fShutdown, true);
 
-    int rc = hdaR3StreamAsyncIONotify(pStream);
+    int rc = hdaR3StreamAsyncIONotify(pStreamR3);
     AssertRC(rc);
 
     int rcThread;
-    rc = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread);
+    rc = RTThreadWait(pAIO->hThread, 30 * 1000 /* 30s timeout */, &rcThread);
     LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc, rcThread));
 
     if (RT_SUCCESS(rc))
     {
+        pAIO->hThread = NIL_RTTHREAD;
+
         rc = RTCritSectDelete(&pAIO->CritSect);
         AssertRC(rc);
 
-        rc = RTSemEventDestroy(pAIO->Event);
+        rc = RTSemEventDestroy(pAIO->hEvent);
         AssertRC(rc);
+        pAIO->hEvent = NIL_RTSEMEVENT;
 
         pAIO->fStarted  = false;
@@ -1962,5 +1954,5 @@
     }
 
-    LogFunc(("[SD%RU8] Returning %Rrc\n", pStream->u8SD, rc));
+    LogFunc(("[SD%RU8] Returning %Rrc\n", pStreamR3->u8SD, rc));
     return rc;
 }
@@ -1970,9 +1962,9 @@
  *
  * @returns IPRT status code.
- * @param   pStream             HDA stream to notify async I/O thread for.
- */
-int hdaR3StreamAsyncIONotify(PHDASTREAM pStream)
-{
-    return RTSemEventSignal(pStream->State.AIO.Event);
+ * @param   pStreamR3           HDA stream to notify async I/O thread for.
+ */
+static int hdaR3StreamAsyncIONotify(PHDASTREAMR3 pStreamR3)
+{
+    return RTSemEventSignal(pStreamR3->State.AIO.hEvent);
 }
 
@@ -1980,9 +1972,9 @@
  * Locks the async I/O thread of a specific HDA audio stream.
  *
- * @param   pStream             HDA stream to lock async I/O thread for.
- */
-void hdaR3StreamAsyncIOLock(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+ * @param   pStreamR3           HDA stream to lock async I/O thread for.
+ */
+void hdaR3StreamAsyncIOLock(PHDASTREAMR3 pStreamR3)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStreamR3->State.AIO;
 
     if (!ASMAtomicReadBool(&pAIO->fStarted))
@@ -1996,9 +1988,9 @@
  * Unlocks the async I/O thread of a specific HDA audio stream.
  *
- * @param   pStream             HDA stream to unlock async I/O thread for.
- */
-void hdaR3StreamAsyncIOUnlock(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+ * @param   pStreamR3           HDA stream to unlock async I/O thread for.
+ */
+void hdaR3StreamAsyncIOUnlock(PHDASTREAMR3 pStreamR3)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStreamR3->State.AIO;
 
     if (!ASMAtomicReadBool(&pAIO->fStarted))
@@ -2012,12 +2004,12 @@
  * Enables (resumes) or disables (pauses) the async I/O thread.
  *
- * @param   pStream             HDA stream to enable/disable async I/O thread for.
+ * @param   pStreamR3           HDA stream to enable/disable async I/O thread for.
  * @param   fEnable             Whether to enable or disable the I/O thread.
  *
  * @remarks Does not do locking.
  */
-void hdaR3StreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+void hdaR3StreamAsyncIOEnable(PHDASTREAMR3 pStreamR3, bool fEnable)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStreamR3->State.AIO;
     ASMAtomicXchgBool(&pAIO->fEnabled, fEnable);
 }
Index: /trunk/src/VBox/Devices/Audio/HDAStream.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.h	(revision 82449)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.h	(revision 82450)
@@ -34,7 +34,7 @@
 {
     /** Thread handle for the actual I/O thread. */
-    RTTHREAD                Thread;
+    RTTHREAD                hThread;
     /** Event for letting the thread know there is some data to process. */
-    RTSEMEVENT              Event;
+    RTSEMEVENT              hEvent;
     /** Critical section for synchronizing access. */
     RTCRITSECT              CritSect;
@@ -123,18 +123,7 @@
     volatile bool           fRunning;
     /** Unused, padding. */
-    uint8_t                 Padding0[4];
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    /** Asynchronous I/O state members. */
-    HDASTREAMSTATEAIO       AIO;
-#endif
-    /** This stream's data mapping. */
-    HDASTREAMMAP            Mapping;
+    uint8_t                 abPadding0[4];
     /** Current BDLE (Buffer Descriptor List Entry). */
     HDABDLE                 BDLE;
-    /** Circular buffer (FIFO) for holding DMA'ed data. */
-    R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
-#if HC_ARCH_BITS == 32
-    RTR3PTR                 Padding1;
-#endif
     /** Timestamp of the last DMA data transfer. */
     uint64_t                tsTransferLast;
@@ -153,5 +142,5 @@
      *  BDLE interrupt-on-completion (IOC) bits set. */
     uint8_t                 cTransferPendingInterrupts;
-    uint8_t                 Padding2[2];
+    uint8_t                 abPadding2[3];
     /** The stream's timer Hz rate.
      *  This value can can be different from the device's default Hz rate,
@@ -167,4 +156,5 @@
      *  0 if position adjustment handling is done or inactive. */
     uint16_t                cfPosAdjustLeft;
+    uint16_t                u16Padding3;
     /** (Virtual) clock ticks per byte. */
     uint64_t                cTicksPerByte;
@@ -177,17 +167,11 @@
     PDMAUDIOSTREAMCFG       Cfg;
     uint32_t                Padding4;
-#ifdef HDA_USE_DMA_ACCESS_HANDLER
-    /** List of DMA handlers. */
-    RTLISTANCHORR3          lstDMAHandlers;
-#endif
-   /** Timestamp (in ns) of last stream update. */
+    /** Timestamp (in ns) of last stream update. */
     uint64_t                tsLastUpdateNs;
 } HDASTREAMSTATE;
 AssertCompileSizeAlignment(HDASTREAMSTATE, 8);
-/** Pointer to the internal state of an HDA stream. */
-typedef HDASTREAMSTATE *PHDASTREAMSTATE;
-
-/**
- * An HDA stream (SDI / SDO).
+
+/**
+ * An HDA stream (SDI / SDO) - shared.
  *
  * @note This HDA stream has nothing to do with a regular audio stream handled
@@ -232,10 +216,27 @@
     uint16_t                    u16LVI;
     uint16_t                    au16Padding1[2];
-    /** Pointer to the HDA state this stream is attached to. */
-    R3PTRTYPE(PHDASTATE)        pHDAState;
+    /** The timer for pumping data thru the attached LUN drivers. */
+    TMTIMERHANDLE               hTimer;
+    /** Internal state of this stream. */
+    HDASTREAMSTATE              State;
+} HDASTREAM;
+/** Pointer to an HDA stream (SDI / SDO).  */
+typedef HDASTREAM *PHDASTREAM;
+
+
+/**
+ * An HDA stream (SDI / SDO) - ring-3 bits.
+ */
+typedef struct HDASTREAMR3
+{
+    /** Stream descriptor number (SDn). */
+    uint8_t                     u8SD;
+    uint8_t                     abPadding[7];
+    /** The shared state for the parent HDA device. */
+    R3PTRTYPE(PHDASTATE)        pHDAStateShared;
+    /** The ring-3 state for the parent HDA device. */
+    R3PTRTYPE(PHDASTATER3)      pHDAStateR3;
     /** Pointer to HDA sink this stream is attached to. */
     R3PTRTYPE(PHDAMIXERSINK)    pMixSink;
-    /** The timer for pumping data thru the attached LUN drivers. */
-    TMTIMERHANDLE               hTimer;
 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     /** The stream's critical section to serialize access between the async I/O
@@ -244,21 +245,24 @@
 #endif
     /** Internal state of this stream. */
-    HDASTREAMSTATE              State;
-    /** Debug information. */
+    struct
+    {
+        /** This stream's data mapping. */
+        HDASTREAMMAP            Mapping;
+        /** Circular buffer (FIFO) for holding DMA'ed data. */
+        R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
+#ifdef HDA_USE_DMA_ACCESS_HANDLER
+        /** List of DMA handlers. */
+        RTLISTANCHORR3          lstDMAHandlers;
+#endif
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        /** Asynchronous I/O state members. */
+        HDASTREAMSTATEAIO       AIO;
+#endif
+    } State;
+    /** Debug bits. */
     HDASTREAMDEBUG              Dbg;
-} HDASTREAM;
+} HDASTREAMR3;
 /** Pointer to an HDA stream (SDI / SDO).  */
-typedef HDASTREAM *PHDASTREAM;
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-/**
- * HDA stream thread context (arguments).
- */
-typedef struct HDASTREAMTHREADCTX
-{
-    PHDASTATE  pThis;
-    PHDASTREAM pStream;
-} HDASTREAMTHREADCTX, *PHDASTREAMTHREADCTX;
-#endif
+typedef HDASTREAMR3 *PHDASTREAMR3;
 
 #ifdef IN_RING3
@@ -267,23 +271,28 @@
  * @{
  */
-int               hdaR3StreamCreate(PHDASTREAM pStream, PHDASTATE pThis, uint8_t u8SD);
-void              hdaR3StreamDestroy(PHDASTREAM pStream);
-int               hdaR3StreamInit(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint8_t uSD);
-void              hdaR3StreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD);
-int               hdaR3StreamEnable(PHDASTREAM pStream, bool fEnable);
-uint32_t          hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStream);
-void              hdaR3StreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB);
-uint32_t          hdaR3StreamGetFree(PHDASTREAM pStream);
-uint32_t          hdaR3StreamGetUsed(PHDASTREAM pStream);
-bool              hdaR3StreamTransferIsScheduled(PHDASTREAM pStream, uint64_t tsNow);
-uint64_t          hdaR3StreamTransferGetNext(PHDASTREAM pStream);
-void              hdaR3StreamLock(PHDASTREAM pStream);
-void              hdaR3StreamUnlock(PHDASTREAM pStream);
-int               hdaR3StreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead);
-int               hdaR3StreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
-void              hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTREAM pStream, bool fAsync);
+int                 hdaR3StreamConstruct(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PHDASTATE pThis,
+                                         PHDASTATER3 pThisCC, uint8_t uSD);
+void                hdaR3StreamDestroy(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
+int                 hdaR3StreamSetUp(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
+                                     PHDASTREAMR3 pStreamR3, uint8_t uSD);
+void                hdaR3StreamReset(PHDASTATE pThis, PHDASTATER3 pThisCC,
+                                     PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD);
+int                 hdaR3StreamEnable(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable);
+/* uint32_t            hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAMR3 pStreamShared); - only used in HDAStream.cpp */
+/*void                hdaR3StreamSetPosition(PHDASTREAM pStream, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB); - only used in HDAStream.cpp */
+/*uint32_t            hdaR3StreamGetFree(PHDASTREAM pStream); - only used in HDAStream.cpp */
+/*uint32_t            hdaR3StreamGetUsed(PHDASTREAM pStream); - only used in HDAStream.cpp */
+bool                hdaR3StreamTransferIsScheduled(PHDASTREAM pStreamShared, uint64_t tsNow);
+uint64_t            hdaR3StreamTransferGetNext(PHDASTREAM pStreamShared);
+void                hdaR3StreamLock(PHDASTREAMR3 pStreamR3);
+void                hdaR3StreamUnlock(PHDASTREAMR3 pStreamR3);
+/* int                 hdaR3StreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead); - only used in HDAStream.cpp */
+/*int                 hdaR3StreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); - only used in HDAStream.cpp */
+void                hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
+                                      PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer);
+PHDASTREAM          hdaR3StreamR3ToShared(PHDASTREAMR3 pStreamCC);
 # ifdef HDA_USE_DMA_ACCESS_HANDLER
-bool              hdaR3StreamRegisterDMAHandlers(PHDASTREAM pStream);
-void              hdaR3StreamUnregisterDMAHandlers(PHDASTREAM pStream);
+bool                hdaR3StreamRegisterDMAHandlers(PHDASTREAM pStream);
+void                hdaR3StreamUnregisterDMAHandlers(PHDASTREAM pStream);
 # endif
 /** @} */
@@ -293,11 +302,8 @@
  */
 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-DECLCALLBACK(int) hdaR3StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser);
-int               hdaR3StreamAsyncIOCreate(PHDASTREAM pStream);
-int               hdaR3StreamAsyncIODestroy(PHDASTREAM pStream);
-int               hdaR3StreamAsyncIONotify(PHDASTREAM pStream);
-void              hdaR3StreamAsyncIOLock(PHDASTREAM pStream);
-void              hdaR3StreamAsyncIOUnlock(PHDASTREAM pStream);
-void              hdaR3StreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable);
+int                 hdaR3StreamAsyncIOCreate(PHDASTREAMR3 pStreamR3);
+void                hdaR3StreamAsyncIOLock(PHDASTREAMR3 pStreamR3);
+void                hdaR3StreamAsyncIOUnlock(PHDASTREAMR3 pStreamR3);
+void                hdaR3StreamAsyncIOEnable(PHDASTREAMR3 pStreamR3, bool fEnable);
 # endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */
 /** @} */
