Index: /trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 67898)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 67899)
@@ -1,5 +1,5 @@
 /* $Id$ */
 /** @file
- * DevHDA - VBox Intel HD Audio Controller.
+ * DevHDA.cpp - VBox Intel HD Audio Controller.
  *
  * Implemented against the specifications found in "High Definition Audio
@@ -47,5 +47,10 @@
 #include "AudioMixBuffer.h"
 #include "AudioMixer.h"
+
+#include "DevHDA.h"
+#include "DevHDACommon.h"
+
 #include "HDACodec.h"
+#include "HDAStream.h"
 # if defined(VBOX_WITH_HDA_AUDIO_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_AUDIO_HDA_51_SURROUND)
 #  include "HDAStreamChannel.h"
@@ -53,5 +58,5 @@
 #include "HDAStreamMap.h"
 #include "HDAStreamPeriod.h"
-#include "DevHDACommon.h"
+
 #include "DrvAudio.h"
 
@@ -107,604 +112,8 @@
 #endif
 
-/** Default timer frequency (in Hz).
- *
- *  Note: Keep in mind that the Hz rate has nothing to do with samples rates
- *        or DMA / interrupt timing -- it's purely needed in order to drive
- *        the data flow at a constant (and sufficient) rate.
- *
- *        Lowering this value can ask for trouble, as backends then can run
- *        into data underruns. */
-#define HDA_TIMER_HZ            200
-
-/** HDA's (fixed) audio frame size in bytes.
- *  We only support 16-bit stereo frames at the moment. */
-#define HDA_FRAME_SIZE          4
-
-/**
- * At the moment we support 4 input + 4 output streams max, which is 8 in total.
- * Bidirectional streams are currently *not* supported.
- *
- * Note: When changing any of those values, be prepared for some saved state
- *       fixups / trouble!
- */
-#define HDA_MAX_SDI             4
-#define HDA_MAX_SDO             4
-#define HDA_MAX_STREAMS         (HDA_MAX_SDI + HDA_MAX_SDO)
-AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
-
-/** Number of general registers. */
-#define HDA_NUM_GENERAL_REGS    34
-/** Number of total registers in the HDA's register map. */
-#define HDA_NUM_REGS            (HDA_NUM_GENERAL_REGS + (HDA_MAX_STREAMS * 10 /* Each stream descriptor has 10 registers */))
-/** Total number of stream tags (channels). Index 0 is reserved / invalid. */
-#define HDA_MAX_TAGS            16
-
-/**
- * NB: Register values stored in memory (au32Regs[]) are indexed through
- * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
- * register descriptors in g_aHdaRegMap[] are indexed through the
- * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
- *
- * The au32Regs[] layout is kept unchanged for saved state
- * compatibility.
- */
-
-/* Registers */
-#define HDA_REG_IND_NAME(x)                 HDA_REG_##x
-#define HDA_MEM_IND_NAME(x)                 HDA_RMX_##x
-#define HDA_REG_IND(pThis, x)               ((pThis)->au32Regs[g_aHdaRegMap[x].mem_idx])
-#define HDA_REG(pThis, x)                   (HDA_REG_IND((pThis), HDA_REG_IND_NAME(x)))
-
-
-#define HDA_REG_GCAP                0 /* range 0x00-0x01*/
-#define HDA_RMX_GCAP                0
-/* GCAP HDASpec 3.3.2 This macro encodes the following information about HDA in a compact manner:
- * oss (15:12) - number of output streams supported
- * iss (11:8)  - number of input streams supported
- * bss (7:3)   - number of bidirectional streams supported
- * bds (2:1)   - number of serial data out (SDO) signals supported
- * b64sup (0)  - 64 bit addressing supported.
- */
-#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \
-    (  (((oss)   & 0xF)  << 12) \
-     | (((iss)   & 0xF)  << 8)  \
-     | (((bss)   & 0x1F) << 3)  \
-     | (((bds)   & 0x3)  << 2)  \
-     | ((b64sup) & 1))
-
-#define HDA_REG_VMIN                1 /* 0x02 */
-#define HDA_RMX_VMIN                1
-
-#define HDA_REG_VMAJ                2 /* 0x03 */
-#define HDA_RMX_VMAJ                2
-
-#define HDA_REG_OUTPAY              3 /* 0x04-0x05 */
-#define HDA_RMX_OUTPAY              3
-
-#define HDA_REG_INPAY               4 /* 0x06-0x07 */
-#define HDA_RMX_INPAY               4
-
-#define HDA_REG_GCTL                5 /* 0x08-0x0B */
-#define HDA_RMX_GCTL                5
-#define HDA_GCTL_UNSOL              RT_BIT(8)   /* Accept Unsolicited Response Enable */
-#define HDA_GCTL_FCNTRL             RT_BIT(1)   /* Flush Control */
-#define HDA_GCTL_CRST               RT_BIT(0)   /* Controller Reset */
-
-#define HDA_REG_WAKEEN              6 /* 0x0C */
-#define HDA_RMX_WAKEEN              6
-
-#define HDA_REG_STATESTS            7 /* 0x0E */
-#define HDA_RMX_STATESTS            7
-#define HDA_STATESTS_SCSF_MASK      0x7 /* State Change Status Flags (6.2.8). */
-
-#define HDA_REG_GSTS                8 /* 0x10-0x11*/
-#define HDA_RMX_GSTS                8
-#define HDA_GSTS_FSTS               RT_BIT(1)   /* Flush Status */
-
-#define HDA_REG_OUTSTRMPAY          9  /* 0x18 */
-#define HDA_RMX_OUTSTRMPAY          112
-
-#define HDA_REG_INSTRMPAY           10 /* 0x1a */
-#define HDA_RMX_INSTRMPAY           113
-
-#define HDA_REG_INTCTL              11 /* 0x20 */
-#define HDA_RMX_INTCTL              9
-#define HDA_INTCTL_GIE              RT_BIT(31)  /* Global Interrupt Enable */
-#define HDA_INTCTL_CIE              RT_BIT(30)  /* Controller Interrupt Enable */
-/* Bits 0-29 correspond to streams 0-29. */
-#define HDA_STRMINT_MASK            0xFF        /* Streams 0-7 implemented. Applies to INTCTL and INTSTS. */
-
-#define HDA_REG_INTSTS              12 /* 0x24 */
-#define HDA_RMX_INTSTS              10
-#define HDA_INTSTS_GIS              RT_BIT(31)  /* Global Interrupt Status */
-#define HDA_INTSTS_CIS              RT_BIT(30)  /* Controller Interrupt Status */
-/* Bits 0-29 correspond to streams 0-29. */
-
-#define HDA_REG_WALCLK              13 /* 0x30 */
-/* NB: HDA_RMX_WALCLK is not defined because the register is not stored in memory. */
-
-/* Note: The HDA specification defines a SSYNC register at offset 0x38. The
- * ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches
- * the datasheet.
- */
-#define HDA_REG_SSYNC               14 /* 0x34 */
-#define HDA_RMX_SSYNC               12
-
-#define HDA_REG_CORBLBASE           15 /* 0x40 */
-#define HDA_RMX_CORBLBASE           13
-
-#define HDA_REG_CORBUBASE           16 /* 0x44 */
-#define HDA_RMX_CORBUBASE           14
-
-#define HDA_REG_CORBWP              17 /* 0x48 */
-#define HDA_RMX_CORBWP              15
-
-#define HDA_REG_CORBRP              18 /* 0x4A */
-#define HDA_RMX_CORBRP              16
-#define HDA_CORBRP_RST              RT_BIT(15)  /* CORB Read Pointer Reset */
-
-#define HDA_REG_CORBCTL             19 /* 0x4C */
-#define HDA_RMX_CORBCTL             17
-#define HDA_CORBCTL_DMA             RT_BIT(1)   /* Enable CORB DMA Engine */
-#define HDA_CORBCTL_CMEIE           RT_BIT(0)   /* CORB Memory Error Interrupt Enable */
-
-#define HDA_REG_CORBSTS             20 /* 0x4D */
-#define HDA_RMX_CORBSTS             18
-
-#define HDA_REG_CORBSIZE            21 /* 0x4E */
-#define HDA_RMX_CORBSIZE            19
-/* NB: Up to and including ICH 10, sizes of CORB and RIRB are fixed at 256 entries. */
-
-#define HDA_REG_RIRBLBASE           22 /* 0x50 */
-#define HDA_RMX_RIRBLBASE           20
-
-#define HDA_REG_RIRBUBASE           23 /* 0x54 */
-#define HDA_RMX_RIRBUBASE           21
-
-#define HDA_REG_RIRBWP              24 /* 0x58 */
-#define HDA_RMX_RIRBWP              22
-#define HDA_RIRBWP_RST              RT_BIT(15)  /* RIRB Write Pointer Reset */
-
-#define HDA_REG_RINTCNT             25 /* 0x5A */
-#define HDA_RMX_RINTCNT             23
-#define RINTCNT_N(pThis)            (HDA_REG(pThis, RINTCNT) & 0xff)
-
-#define HDA_REG_RIRBCTL             26 /* 0x5C */
-#define HDA_RMX_RIRBCTL             24
-#define HDA_RIRBCTL_ROIC            RT_BIT(2)   /* Response Overrun Interrupt Control */
-#define HDA_RIRBCTL_RDMAEN          RT_BIT(1)   /* RIRB DMA Enable */
-#define HDA_RIRBCTL_RINTCTL         RT_BIT(0)   /* Response Interrupt Control */
-
-#define HDA_REG_RIRBSTS             27 /* 0x5D */
-#define HDA_RMX_RIRBSTS             25
-#define HDA_RIRBSTS_RIRBOIS         RT_BIT(2)   /* Response Overrun Interrupt Status */
-#define HDA_RIRBSTS_RINTFL          RT_BIT(0)   /* Response Interrupt Flag */
-
-#define HDA_REG_RIRBSIZE            28 /* 0x5E */
-#define HDA_RMX_RIRBSIZE            26
-
-#define HDA_REG_IC                  29 /* 0x60 */
-#define HDA_RMX_IC                  27
-
-#define HDA_REG_IR                  30 /* 0x64 */
-#define HDA_RMX_IR                  28
-
-#define HDA_REG_IRS                 31 /* 0x68 */
-#define HDA_RMX_IRS                 29
-#define HDA_IRS_IRV                 RT_BIT(1)   /* Immediate Result Valid */
-#define HDA_IRS_ICB                 RT_BIT(0)   /* Immediate Command Busy */
-
-#define HDA_REG_DPLBASE             32 /* 0x70 */
-#define HDA_RMX_DPLBASE             30
-
-#define HDA_REG_DPUBASE             33 /* 0x74 */
-#define HDA_RMX_DPUBASE             31
-
-#define DPBASE_ADDR_MASK            (~(uint64_t)0x7f)
-
-#define HDA_STREAM_REG_DEF(name, num)           (HDA_REG_SD##num##name)
-#define HDA_STREAM_RMX_DEF(name, num)           (HDA_RMX_SD##num##name)
-/* Note: sdnum here _MUST_ be stream reg number [0,7]. */
-#define HDA_STREAM_REG(pThis, name, sdnum)      (HDA_REG_IND((pThis), HDA_REG_SD0##name + (sdnum) * 10))
-
-#define HDA_SD_NUM_FROM_REG(pThis, func, reg)   ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
-
-/** @todo Condense marcos! */
-
-#define HDA_REG_SD0CTL              HDA_NUM_GENERAL_REGS /* 0x80; other streams offset by 0x20 */
-#define HDA_RMX_SD0CTL              32
-#define HDA_RMX_SD1CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
-#define HDA_RMX_SD2CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 20)
-#define HDA_RMX_SD3CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 30)
-#define HDA_RMX_SD4CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 40)
-#define HDA_RMX_SD5CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 50)
-#define HDA_RMX_SD6CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 60)
-#define HDA_RMX_SD7CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 70)
-
-#define HDA_SDCTL_NUM_MASK          0xF
-#define HDA_SDCTL_NUM_SHIFT         20
-#define HDA_SDCTL_DIR               RT_BIT(19)  /* Direction (Bidirectional streams only!) */
-#define HDA_SDCTL_TP                RT_BIT(18)  /* Traffic Priority (PCI Express) */
-#define HDA_SDCTL_STRIPE_MASK       0x3
-#define HDA_SDCTL_STRIPE_SHIFT      16
-#define HDA_SDCTL_DEIE              RT_BIT(4)   /* Descriptor Error Interrupt Enable */
-#define HDA_SDCTL_FEIE              RT_BIT(3)   /* FIFO Error Interrupt Enable */
-#define HDA_SDCTL_IOCE              RT_BIT(2)   /* Interrupt On Completion Enable */
-#define HDA_SDCTL_RUN               RT_BIT(1)   /* Stream Run */
-#define HDA_SDCTL_SRST              RT_BIT(0)   /* Stream Reset */
-
-#define HDA_REG_SD0STS              35 /* 0x83; other streams offset by 0x20 */
-#define HDA_RMX_SD0STS              33
-#define HDA_RMX_SD1STS              (HDA_STREAM_RMX_DEF(STS, 0) + 10)
-#define HDA_RMX_SD2STS              (HDA_STREAM_RMX_DEF(STS, 0) + 20)
-#define HDA_RMX_SD3STS              (HDA_STREAM_RMX_DEF(STS, 0) + 30)
-#define HDA_RMX_SD4STS              (HDA_STREAM_RMX_DEF(STS, 0) + 40)
-#define HDA_RMX_SD5STS              (HDA_STREAM_RMX_DEF(STS, 0) + 50)
-#define HDA_RMX_SD6STS              (HDA_STREAM_RMX_DEF(STS, 0) + 60)
-#define HDA_RMX_SD7STS              (HDA_STREAM_RMX_DEF(STS, 0) + 70)
-
-#define HDA_SDSTS_FIFORDY           RT_BIT(5)   /* FIFO Ready */
-#define HDA_SDSTS_DESE              RT_BIT(4)   /* Descriptor Error */
-#define HDA_SDSTS_FIFOE             RT_BIT(3)   /* FIFO Error */
-#define HDA_SDSTS_BCIS              RT_BIT(2)   /* Buffer Completion Interrupt Status */
-
-#define HDA_REG_SD0LPIB             36 /* 0x84; other streams offset by 0x20 */
-#define HDA_REG_SD1LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 10) /* 0xA4 */
-#define HDA_REG_SD2LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 20) /* 0xC4 */
-#define HDA_REG_SD3LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 30) /* 0xE4 */
-#define HDA_REG_SD4LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 40) /* 0x104 */
-#define HDA_REG_SD5LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 50) /* 0x124 */
-#define HDA_REG_SD6LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 60) /* 0x144 */
-#define HDA_REG_SD7LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 70) /* 0x164 */
-#define HDA_RMX_SD0LPIB             34
-#define HDA_RMX_SD1LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 10)
-#define HDA_RMX_SD2LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 20)
-#define HDA_RMX_SD3LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 30)
-#define HDA_RMX_SD4LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 40)
-#define HDA_RMX_SD5LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 50)
-#define HDA_RMX_SD6LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 60)
-#define HDA_RMX_SD7LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 70)
-
-#define HDA_REG_SD0CBL              37 /* 0x88; other streams offset by 0x20 */
-#define HDA_RMX_SD0CBL              35
-#define HDA_RMX_SD1CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 10)
-#define HDA_RMX_SD2CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 20)
-#define HDA_RMX_SD3CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 30)
-#define HDA_RMX_SD4CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 40)
-#define HDA_RMX_SD5CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 50)
-#define HDA_RMX_SD6CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 60)
-#define HDA_RMX_SD7CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 70)
-
-#define HDA_REG_SD0LVI              38 /* 0x8C; other streams offset by 0x20 */
-#define HDA_RMX_SD0LVI              36
-#define HDA_RMX_SD1LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 10)
-#define HDA_RMX_SD2LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 20)
-#define HDA_RMX_SD3LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 30)
-#define HDA_RMX_SD4LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 40)
-#define HDA_RMX_SD5LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 50)
-#define HDA_RMX_SD6LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 60)
-#define HDA_RMX_SD7LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 70)
-
-#define HDA_REG_SD0FIFOW            39 /* 0x8E; other streams offset by 0x20 */
-#define HDA_RMX_SD0FIFOW            37
-#define HDA_RMX_SD1FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 10)
-#define HDA_RMX_SD2FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 20)
-#define HDA_RMX_SD3FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 30)
-#define HDA_RMX_SD4FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 40)
-#define HDA_RMX_SD5FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 50)
-#define HDA_RMX_SD6FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 60)
-#define HDA_RMX_SD7FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 70)
-
-/*
- * ICH6 datasheet defined limits for FIFOW values (18.2.38).
- */
-#define HDA_SDFIFOW_8B              0x2
-#define HDA_SDFIFOW_16B             0x3
-#define HDA_SDFIFOW_32B             0x4
-
-#define HDA_REG_SD0FIFOS            40 /* 0x90; other streams offset by 0x20 */
-#define HDA_RMX_SD0FIFOS            38
-#define HDA_RMX_SD1FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 10)
-#define HDA_RMX_SD2FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 20)
-#define HDA_RMX_SD3FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 30)
-#define HDA_RMX_SD4FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 40)
-#define HDA_RMX_SD5FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 50)
-#define HDA_RMX_SD6FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 60)
-#define HDA_RMX_SD7FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 70)
-
-/*
- * ICH6 datasheet defines limits for FIFOS registers (18.2.39)
- * formula: size - 1
- * Other values not listed are not supported.
- */
-/** Maximum FIFO size (in bytes). */
-#define HDA_FIFO_MAX                256
-
-#define HDA_SDIFIFO_120B            0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
-#define HDA_SDIFIFO_160B            0x9F /* 20-, 24-bit Input Streams Streams */
-
-#define HDA_SDOFIFO_16B             0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_32B             0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_64B             0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_128B            0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_192B            0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_256B            0xFF /* 20-, 24-bit Output Streams */
-
-#define HDA_REG_SD0FMT              41 /* 0x92; other streams offset by 0x20 */
-#define HDA_RMX_SD0FMT              39
-#define HDA_RMX_SD1FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 10)
-#define HDA_RMX_SD2FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 20)
-#define HDA_RMX_SD3FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 30)
-#define HDA_RMX_SD4FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 40)
-#define HDA_RMX_SD5FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 50)
-#define HDA_RMX_SD6FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 60)
-#define HDA_RMX_SD7FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 70)
-
-#define HDA_REG_SD0BDPL             42 /* 0x98; other streams offset by 0x20 */
-#define HDA_RMX_SD0BDPL             40
-#define HDA_RMX_SD1BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 10)
-#define HDA_RMX_SD2BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 20)
-#define HDA_RMX_SD3BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 30)
-#define HDA_RMX_SD4BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 40)
-#define HDA_RMX_SD5BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 50)
-#define HDA_RMX_SD6BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 60)
-#define HDA_RMX_SD7BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 70)
-
-#define HDA_REG_SD0BDPU             43 /* 0x9C; other streams offset by 0x20 */
-#define HDA_RMX_SD0BDPU             41
-#define HDA_RMX_SD1BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 10)
-#define HDA_RMX_SD2BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 20)
-#define HDA_RMX_SD3BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 30)
-#define HDA_RMX_SD4BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 40)
-#define HDA_RMX_SD5BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 50)
-#define HDA_RMX_SD6BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 60)
-#define HDA_RMX_SD7BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 70)
-
-#define HDA_BDLE_FLAG_IOC           RT_BIT(0) /* Interrupt on completion (IOC). */
-
-#define HDA_CODEC_CAD_SHIFT         28
-/* Encodes the (required) LUN into a codec command. */
-#define HDA_CODEC_CMD(cmd, lun)     ((cmd) | (lun << HDA_CODEC_CAD_SHIFT))
-
-
 
 /*********************************************************************************************************************************
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
-
-/**
- * Internal state of a Buffer Descriptor List Entry (BDLE),
- * needed to keep track of the data needed for the actual device
- * emulation.
- */
-typedef struct HDABDLESTATE
-{
-    /** Own index within the BDL (Buffer Descriptor List). */
-    uint32_t     u32BDLIndex;
-    /** Number of bytes below the stream's FIFO watermark (SDFIFOW).
-     *  Used to check if we need fill up the FIFO again. */
-    uint32_t     cbBelowFIFOW;
-    /** Current offset in DMA buffer (in bytes).*/
-    uint32_t     u32BufOff;
-    uint32_t     Padding;
-} HDABDLESTATE, *PHDABDLESTATE;
-
-/**
- * BDL description structure.
- * Do not touch this, as this must match to the HDA specs.
- */
-typedef struct HDABDLEDESC
-{
-    /** Starting address of the actual buffer. Must be 128-bit aligned. */
-    uint64_t     u64BufAdr;
-    /** Size of the actual buffer (in bytes). */
-    uint32_t     u32BufSize;
-    /** Bit 0: Interrupt on completion; the controller will generate
-     *  an interrupt when the last byte of the buffer has been
-     *  fetched by the DMA engine.
-     *
-     *  Rest is reserved for further use and must be 0. */
-    uint32_t     fFlags;
-} HDABDLEDESC, *PHDABDLEDESC;
-AssertCompileSize(HDABDLEDESC, 16); /* Always 16 byte. Also must be aligned on 128-byte boundary. */
-
-/**
- * Buffer Descriptor List Entry (BDLE) (3.6.3).
- */
-typedef struct HDABDLE
-{
-    /** The actual BDL description. */
-    HDABDLEDESC  Desc;
-    /** Internal state of this BDLE.
-     *  Not part of the actual BDLE registers. */
-    HDABDLESTATE State;
-} HDABDLE, *PHDABDLE;
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-/**
- * Structure keeping the HDA stream's state for asynchronous I/O.
- */
-typedef struct HDASTREAMSTATEAIO
-{
-    /** Thread handle for the actual I/O thread. */
-    RTTHREAD              Thread;
-    /** Event for letting the thread know there is some data to process. */
-    RTSEMEVENT            Event;
-    /** Critical section for synchronizing access. */
-    RTCRITSECT            CritSect;
-    /** Started indicator. */
-    volatile bool         fStarted;
-    /** Shutdown indicator. */
-    volatile bool         fShutdown;
-    /** Whether the thread should do any data processing or not. */
-    volatile bool         fEnabled;
-    uint32_t              Padding1;
-} HDASTREAMSTATEAIO, *PHDASTREAMSTATEAIO;
-#endif
-
-/**
- * Internal state of a HDA stream.
- */
-typedef struct HDASTREAMSTATE
-{
-    /** Current BDLE to use. Wraps around to 0 if
-     *  maximum (cBDLE) is reached. */
-    uint16_t                uCurBDLE;
-    /** Flag indicating whether this stream currently is
-     *  in reset mode and therefore not acccessible by the guest. */
-    volatile bool           fInReset;
-    /** Unused, padding. */
-    uint32_t                Padding0;
-    /** Critical section to serialize access. */
-    RTCRITSECT              CritSect;
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    /** Asynchronous I/O state members. */
-    HDASTREAMSTATEAIO       AIO;
-#endif
-    /** This stream's data mapping. */
-    HDASTREAMMAPPING        Mapping;
-    /** Current BDLE (Buffer Descriptor List Entry). */
-    HDABDLE                 BDLE;
-    /** Circular buffer (FIFO) for holding DMA'ed data. */
-    R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
-    /** Timestamp of the last success DMA data transfer.
-     *  Used to calculate the time actually elapsed between two transfers. */
-    uint64_t                uTimerTS;
-    /** The stream's period. Need for timing. */
-    HDASTREAMPERIOD         Period;
-    /** The stream's current configuration.
-     *  Should match SDFMT. */
-    PDMAUDIOSTREAMCFG       strmCfg;
-#ifdef HDA_USE_DMA_ACCESS_HANDLER
-    /** List of DMA handlers. */
-    RTLISTANCHORR3          lstDMAHandlers;
-#endif
-    /** Unused, padding. */
-    uint8_t                 Padding1[3];
-} HDASTREAMSTATE, *PHDASTREAMSTATE;
-
-/**
- * Structure defining an HDA mixer sink.
- * Its purpose is to know which audio mixer sink is bound to
- * which SDn (SDI/SDO) device stream.
- *
- * This is needed in order to handle interleaved streams
- * (that is, multiple channels in one stream) or non-interleaved
- * streams (each channel has a dedicated stream).
- *
- * This is only known to the actual device emulation level.
- */
-typedef struct HDAMIXERSINK
-{
-    /** SDn ID this sink is assigned to. 0 if not assigned. */
-    uint8_t                uSD;
-    /** Channel ID of SDn ID. Only valid if SDn ID is valid. */
-    uint8_t                uChannel;
-    uint8_t                Padding[3];
-    /** Pointer to the actual audio mixer sink. */
-    R3PTRTYPE(PAUDMIXSINK) pMixSink;
-} HDAMIXERSINK, *PHDAMIXERSINK;
-
-#if defined (DEBUG) || defined(HDA_USE_DMA_ACCESS_HANDLER)
-typedef struct HDASTREAMDBGINFO
-{
-    /** Critical section to serialize access if needed. */
-    RTCRITSECT              CritSect;
-    uint32_t                Padding1[2];
-    /** Number of total read accesses. */
-    uint64_t                cReadsTotal;
-    /** Number of total DMA bytes read. */
-    uint64_t                cbReadTotal;
-    /** Timestamp (in ns) of last read access. */
-    uint64_t                tsLastReadNs;
-    /** Number of total write accesses. */
-    uint64_t                cWritesTotal;
-    /** Number of total DMA bytes written. */
-    uint64_t                cbWrittenTotal;
-    /** Number of total write accesses since last iteration (Hz). */
-    uint64_t                cWritesHz;
-    /** Number of total DMA bytes written since last iteration (Hz). */
-    uint64_t                cbWrittenHz;
-    /** Timestamp (in ns) of beginning a new write slot. */
-    uint64_t                tsWriteSlotBegin;
-    /** Number of current silence samples in a (consecutive) row. */
-    uint64_t                csSilence;
-    /** Number of silent samples in a row to consider an audio block as audio gap (silence). */
-    uint64_t                cSilenceThreshold;
-    /** How many bytes to skip in an audio stream before detecting silence.
-     *  (useful for intros and silence at the beginning of a song). */
-    uint64_t                cbSilenceReadMin;
-} HDASTREAMDBGINFO ,*PHDASTREAMDBGINFO;
-#endif /* defined (DEBUG) || defined(HDA_USE_DMA_ACCESS_HANDLER) */
-
-/**
- * Structure for keeping a HDA stream (SDI / SDO).
- *
- * Note: This HDA stream has nothing to do with a regular audio stream handled
- * by the audio connector or the audio mixer. This HDA stream is a serial data in/out
- * stream (SDI/SDO) defined in hardware and can contain multiple audio streams
- * in one single SDI/SDO (interleaving streams).
- *
- * How a specific SDI/SDO is mapped to our internal audio streams relies on the
- * stream channel mappings.
- *
- * Contains only register values which do *not* change until a
- * stream reset occurs.
- */
-typedef struct HDASTREAM
-{
-    /** Stream descriptor number (SDn). */
-    uint8_t                  u8SD;
-    uint8_t                  Padding0[7];
-    /** DMA base address (SDnBDPU - SDnBDPL). */
-    uint64_t                 u64BDLBase;
-    /** Cyclic Buffer Length (SDnCBL).
-     *  Represents the size of the ring buffer. */
-    uint32_t                 u32CBL;
-    /** Format (SDnFMT). */
-    uint16_t                 u16FMT;
-    /** FIFO Size (FIFOS).
-     *  Maximum number of bytes that may have been DMA'd into
-     *  memory but not yet transmitted on the link. */
-    uint16_t                 u16FIFOS;
-    /** FIFO Watermark. */
-    uint16_t                 u16FIFOW;
-    /** Last Valid Index (SDnLVI). */
-    uint16_t                 u16LVI;
-    uint16_t                 Padding1[2];
-    /** Pointer to the HDA state this stream is attached to. */
-    R3PTRTYPE(PHDASTATE)     pHDAState;
-    /** Pointer to HDA sink this stream is attached to. */
-    R3PTRTYPE(PHDAMIXERSINK) pMixSink;
-    /** Internal state of this stream. */
-    HDASTREAMSTATE           State;
-#ifdef DEBUG
-    /** Debug information. */
-    HDASTREAMDBGINFO         Dbg;
-#endif
-} HDASTREAM, *PHDASTREAM;
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-/**
- * Structure for keeping a HDA stream thread context.
- */
-typedef struct HDASTREAMTHREADCTX
-{
-    PHDASTATE  pThis;
-    PHDASTREAM pStream;
-} HDASTREAMTHREADCTX, *PHDASTREAMTHREADCTX;
-#endif
-
-/**
- * Structure for mapping a stream tag to an HDA stream.
- */
-typedef struct HDATAG
-{
-    /** Own stream tag. */
-    uint8_t               uTag;
-    uint8_t               Padding[7];
-    /** Pointer to associated stream. */
-    R3PTRTYPE(PHDASTREAM) pStream;
-} HDATAG, *PHDATAG;
 
 /**
@@ -792,144 +201,4 @@
 } HDADRIVER;
 
-#ifdef DEBUG
-/** @todo Make STAM values out of this? */
-typedef struct HDASTATEDBGINFO
-{
-    /** 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;
-} HDASTATEDBGINFO, *PHDASTATEDBGINFO;
-#endif
-
-/**
- * ICH Intel HD Audio Controller state.
- */
-typedef struct HDASTATE
-{
-    /** The PCI device structure. */
-    PDMPCIDEV                          PciDev;
-    /** R3 Pointer to the device instance. */
-    PPDMDEVINSR3                       pDevInsR3;
-    /** R0 Pointer to the device instance. */
-    PPDMDEVINSR0                       pDevInsR0;
-    /** R0 Pointer to the device instance. */
-    PPDMDEVINSRC                       pDevInsRC;
-    /** Padding for alignment. */
-    uint32_t                           u32Padding;
-    /** The base interface for LUN\#0. */
-    PDMIBASE                           IBase;
-    RTGCPHYS                           MMIOBaseAddr;
-    /** The HDA's register set. */
-    uint32_t                           au32Regs[HDA_NUM_REGS];
-    /** Internal stream states. */
-    HDASTREAM                          aStreams[HDA_MAX_STREAMS];
-    /** Mapping table between stream tags and stream states. */
-    HDATAG                             aTags[HDA_MAX_TAGS];
-    /** CORB buffer base address. */
-    uint64_t                           u64CORBBase;
-    /** RIRB buffer base address. */
-    uint64_t                           u64RIRBBase;
-    /** DMA base address.
-     *  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. */
-    uint32_t                           cbCorbBuf;
-    /** Padding for alignment. */
-    uint32_t                           u32Padding1;
-    /** Pointer to RIRB buffer. */
-    R3PTRTYPE(uint64_t *)              pu64RirbBuf;
-    /** Size in bytes of RIRB buffer. */
-    uint32_t                           cbRirbBuf;
-    /** DMA position buffer enable bit. */
-    bool                               fDMAPosition;
-    /** Flag whether the R0 part is enabled. */
-    bool                               fR0Enabled;
-    /** Flag whether the RC part is enabled. */
-    bool                               fRCEnabled;
-    /** Number of active (running) SDn streams. */
-    uint8_t                            cStreamsActive;
-#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
-    /** The timer for pumping data thru the attached LUN drivers. */
-    PTMTIMERR3                         pTimer;
-    /** Flag indicating whether the timer is active or not. */
-    bool                               fTimerActive;
-    uint8_t                            u8Padding1[7];
-    /** Timer ticks per Hz. */
-    uint64_t                           cTimerTicks;
-    /** The current timer expire time (in timer ticks). */
-    uint64_t                           tsTimerExpire;
-#endif
-#ifdef VBOX_WITH_STATISTICS
-# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
-    STAMPROFILE                        StatTimer;
-# endif
-    STAMPROFILE                        StatIn;
-    STAMPROFILE                        StatOut;
-    STAMCOUNTER                        StatBytesRead;
-    STAMCOUNTER                        StatBytesWritten;
-#endif
-    /** 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 WALCLK counter. */
-    uint64_t                           u64WalClk;
-    /** Response Interrupt Count (RINTCNT). */
-    uint8_t                            u8RespIntCnt;
-    /** Current IRQ level. */
-    uint8_t                            u8IRQL;
-    /** Padding for alignment. */
-    uint8_t                            au8Padding2[6];
-#ifdef DEBUG
-    HDASTATEDBGINFO                    Dbg;
-#endif
-} HDASTATE;
-/** Pointer to the ICH Intel HD Audio Controller state. */
-typedef HDASTATE *PHDASTATE;
-
-#ifdef VBOX_WITH_AUDIO_HDA_CALLBACKS
-typedef struct HDACALLBACKCTX
-{
-    PHDASTATE  pThis;
-    PHDADRIVER pDriver;
-} HDACALLBACKCTX, *PHDACALLBACKCTX;
-#endif
-
 
 /*********************************************************************************************************************************
@@ -980,12 +249,4 @@
 /** @} */
 
-/** @name {IOB}SDn utility functions.
- * @{
- */
-#ifdef IN_RING3
-static int hdaSDFMTToPCMProps(uint32_t u32SDFMT, PPDMAUDIOPCMPROPS pProps);
-#endif
-/** @} */
-
 /** @name Generic register read/write functions.
  * @{
@@ -1001,42 +262,4 @@
 static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
 static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
-
-/** @name Stream functions.
- * @{
- */
-#ifdef IN_RING3
-static void          hdaStreamDestroy(PHDASTREAM pStream);
-static int           hdaStreamEnable(PHDASTREAM pStream, bool fEnable);
-static uint32_t      hdaStreamGetUsed(PHDASTREAM pStream);
-static uint32_t      hdaStreamGetFree(PHDASTREAM pStream);
-static int           hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax);
-DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTREAM pStream, uint32_t u32LPIB);
-static void          hdaStreamLock(PHDASTREAM pStream);
-static void          hdaStreamUnlock(PHDASTREAM pStream);
-static int           hdaStreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead);
-static int           hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten);
-static void          hdaStreamUpdate(PHDASTREAM pStream, bool fAsync);
-# ifdef HDA_USE_DMA_ACCESS_HANDLER
-static bool          hdaStreamRegisterDMAHandlers(PHDASTREAM pStream);
-static void          hdaStreamUnregisterDMAHandlers(PHDASTREAM pStream);
-# endif
-#endif /* IN_RING3 */
-/** @} */
-
-/** @name Async I/O stream functions.
- * @{
- */
-#ifdef IN_RING3
-# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-static DECLCALLBACK(int) hdaStreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser);
-static int               hdaStreamAsyncIOCreate(PHDASTREAM pStream);
-static int               hdaStreamAsyncIODestroy(PHDASTREAM pStream);
-static int               hdaStreamAsyncIONotify(PHDASTREAM pStream);
-static void              hdaStreamAsyncIOLock(PHDASTREAM pStream);
-static void              hdaStreamAsyncIOUnlock(PHDASTREAM pStream);
-static void              hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable);
-# endif
-#endif
 /** @} */
 
@@ -1052,15 +275,4 @@
 /** @} */
 
-/** @name BDLE (Buffer Descriptor List Entry) functions.
- * @{
- */
-#ifdef IN_RING3
-static int           hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
-# ifdef LOG_ENABLED
-static void          hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BaseDMA, uint16_t cBDLE);
-# endif
-#endif /* IN_RING3 */
-/** @} */
-
 /** @name Timer functions.
  * @{
@@ -1073,28 +285,8 @@
 /** @} */
 
-/** @name Wall clock (WALCLK) functions.
- * @{
- */
-uint64_t          hdaWalClkGetCurrent(PHDASTATE pThis);
-#ifdef IN_RING3
-bool              hdaWalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce);
-#endif
-/** @} */
 
 /*********************************************************************************************************************************
 *   Global Variables                                                                                                             *
 *********************************************************************************************************************************/
-
-/** Offset of the SD0 register map. */
-#define HDA_REG_DESC_SD0_BASE 0x80
-
-/** Turn a short global register name into an memory index and a stringized name. */
-#define HDA_REG_IDX(abbrev)         HDA_MEM_IND_NAME(abbrev), #abbrev
-
-/** Turns a short stream register name into an memory index and a stringized name. */
-#define HDA_REG_IDX_STRM(reg, suff) HDA_MEM_IND_NAME(reg ## suff), #reg #suff
-
-/** Same as above for a register *not* stored in memory. */
-#define HDA_REG_IDX_NOMEM(abbrev)   0, #abbrev
 
 /** No register description (RD) flags defined. */
@@ -1134,30 +326,5 @@
 
 /* See 302349 p 6.2. */
-static const struct HDAREGDESC
-{
-    /** Register offset in the register space. */
-    uint32_t    offset;
-    /** Size in bytes. Registers of size > 4 are in fact tables. */
-    uint32_t    size;
-    /** Readable bits. */
-    uint32_t    readable;
-    /** Writable bits. */
-    uint32_t    writable;
-    /** Register descriptor (RD) flags of type HDA_RD_FLAG_.
-     *  These are used to specify the handling (read/write)
-     *  policy of the register. */
-    uint32_t    fFlags;
-    /** Read callback. */
-    int       (*pfnRead)(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-    /** Write callback. */
-    int       (*pfnWrite)(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-    /** Index into the register storage array. */
-    uint32_t    mem_idx;
-    /** Abbreviated name. */
-    const char *abbrev;
-    /** Descripton. */
-    const char *desc;
-} g_aHdaRegMap[HDA_NUM_REGS] =
-
+const HDAREGDESC g_aHdaRegMap[HDA_NUM_REGS] =
 {
     /* offset  size     read mask   write mask  flags             read callback     write callback       index + abbrev              */
@@ -1209,15 +376,5 @@
 };
 
-/**
- * HDA register aliases (HDA spec 3.3.45).
- * @remarks Sorted by offReg.
- */
-static const struct
-{
-    /** The alias register offset. */
-    uint32_t    offReg;
-    /** The register index. */
-    int         idxAlias;
-} g_aHdaRegAliases[] =
+const HDAREGALIAS g_aHdaRegAliases[] =
 {
     { 0x2084, HDA_REG_SD0LPIB },
@@ -1228,5 +385,5 @@
     { 0x2124, HDA_REG_SD5LPIB },
     { 0x2144, HDA_REG_SD6LPIB },
-    { 0x2164, HDA_REG_SD7LPIB },
+    { 0x2164, HDA_REG_SD7LPIB }
 };
 
@@ -1321,272 +478,4 @@
 }
 
-/**
- * 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).
- *
- * @returns Set LPIB value.
- * @param   pStream             HDA stream to update read / write position for.
- * @param   u32LPIB             New LPIB (position) value to set.
- */
-DECLINLINE(uint32_t) hdaStreamUpdateLPIB(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);
-
-    LogFlowFunc(("[SD%RU8]: LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
-                 pStream->u8SD, u32LPIB, pThis->fDMAPosition));
-
-    /* Update LPIB in any case. */
-    HDA_STREAM_REG(pThis, LPIB, pStream->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)),
-                                        (void *)&u32LPIB, sizeof(uint32_t));
-        AssertRC(rc2);
-    }
-
-    return u32LPIB;
-}
-
-
-/**
- * Locks an HDA stream for serialized access.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to lock.
- */
-static void hdaStreamLock(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
-    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
-    AssertRC(rc2);
-}
-
-
-/**
- * Unlocks a formerly locked HDA stream.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to unlock.
- */
-static void hdaStreamUnlock(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
-    int rc2 = RTCritSectLeave(&pStream->State.CritSect);
-    AssertRC(rc2);
-}
-
-
-/**
- * Returns the HDA stream of specified stream descriptor number.
- *
- * @return  Pointer to HDA stream, or NULL if none found.
- */
-DECLINLINE(PHDASTREAM) hdaStreamGetFromSD(PHDASTATE pThis, uint8_t uSD)
-{
-    AssertPtrReturn(pThis, NULL);
-    AssertReturn(uSD < HDA_MAX_STREAMS, NULL);
-
-    if (uSD >= HDA_MAX_STREAMS)
-    {
-        AssertMsgFailed(("Invalid / non-handled SD%RU8\n", uSD));
-        return NULL;
-    }
-
-    return &pThis->aStreams[uSD];
-}
-
-
-/**
- * Returns the HDA stream of specified HDA sink.
- *
- * @return  Pointer to HDA stream, or NULL if none found.
- */
-DECLINLINE(PHDASTREAM) hdaSinkGetStream(PHDASTATE pThis, PHDAMIXERSINK pSink)
-{
-    AssertPtrReturn(pThis, NULL);
-    AssertPtrReturn(pSink, NULL);
-
-    /** @todo Do something with the channel mapping here? */
-    return hdaStreamGetFromSD(pThis, pSink->uSD);
-}
-
-
-/**
- * Returns the audio direction of a specified stream descriptor.
- *
- * The register layout specifies that input streams (SDI) come first,
- * followed by the output streams (SDO). So every stream ID below HDA_MAX_SDI
- * is an input stream, whereas everything >= HDA_MAX_SDI is an output stream.
- *
- * Note: SDnFMT register does not provide that information, so we have to judge
- *       for ourselves.
- *
- * @return  Audio direction.
- */
-DECLINLINE(PDMAUDIODIR) hdaGetDirFromSD(uint8_t uSD)
-{
-    AssertReturn(uSD < HDA_MAX_STREAMS, PDMAUDIODIR_UNKNOWN);
-
-    if (uSD < HDA_MAX_SDI)
-        return PDMAUDIODIR_IN;
-
-    return PDMAUDIODIR_OUT;
-}
-#endif /* IN_RING3 */
-
-static uint32_t hdaGetINTSTS(PHDASTATE pThis)
-{
-    uint32_t intSts = 0;
-
-    /* Check controller interrupts (RIRB, STATEST). */
-    if (   (HDA_REG(pThis, RIRBSTS) & HDA_REG(pThis, RIRBCTL) & (HDA_RIRBCTL_ROIC | HDA_RIRBCTL_RINTCTL))
-        /* SDIN State Change Status Flags (SCSF). */
-        || (HDA_REG(pThis, STATESTS) & HDA_STATESTS_SCSF_MASK))
-    {
-        intSts |= HDA_INTSTS_CIS; /* Set the Controller Interrupt Status (CIS). */
-    }
-
-    if (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN))
-    {
-        intSts |= HDA_INTSTS_CIS; /* Touch Controller Interrupt Status (CIS). */
-    }
-
-    /* For each stream, check if any interrupt status bit is set and enabled. */
-    for (uint8_t iStrm = 0; iStrm < HDA_MAX_STREAMS; ++iStrm)
-    {
-        if (HDA_STREAM_REG(pThis, STS, iStrm) & HDA_STREAM_REG(pThis, CTL, iStrm) & (HDA_SDCTL_DEIE | HDA_SDCTL_FEIE  | HDA_SDCTL_IOCE))
-        {
-            Log3Func(("[SD%d] interrupt status set\n", iStrm));
-            intSts |= RT_BIT(iStrm);
-        }
-    }
-
-    if (intSts)
-        intSts |= HDA_INTSTS_GIS; /* Set the Global Interrupt Status (GIS). */
-
-    Log3Func(("-> 0x%x\n", intSts));
-
-    return intSts;
-}
-
-#ifndef DEBUG
-/**
- * Processes (de/asserts) the interrupt according to the HDA's current state.
- *
- * @returns IPRT status code.
- * @param   pThis               HDA state.
- */
-static int hdaProcessInterrupt(PHDASTATE pThis)
-#else
-/**
- * Processes (de/asserts) the interrupt according to the HDA's current state.
- * Debug version.
- *
- * @returns IPRT status code.
- * @param   pThis               HDA state.
- * @param   pszSource           Caller information.
- */
-static int hdaProcessInterrupt(PHDASTATE pThis, const char *pszSource)
-#endif
-{
-    HDA_REG(pThis, INTSTS) = hdaGetINTSTS(pThis);
-
-    Log3Func(("IRQL=%RU8\n", pThis->u8IRQL));
-
-    /* NB: It is possible to have GIS set even when CIE/SIEn are all zero; the GIS bit does
-     * not control the interrupt signal. See Figure 4 on page 54 of the HDA 1.0a spec.
-     */
-
-    /* If global interrupt enable (GIE) is set, check if any enabled interrupts are set. */
-    if (   (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE)
-        && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK)))
-    {
-        if (!pThis->u8IRQL)
-        {
-#ifdef DEBUG
-            if (!pThis->Dbg.IRQ.tsProcessedLastNs)
-                pThis->Dbg.IRQ.tsProcessedLastNs = RTTimeNanoTS();
-
-            const uint64_t tsLastElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsProcessedLastNs;
-
-            if (!pThis->Dbg.IRQ.tsAssertedNs)
-                pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS();
-
-            const uint64_t tsAssertedElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsAssertedNs;
-
-            pThis->Dbg.IRQ.cAsserted++;
-            pThis->Dbg.IRQ.tsAssertedTotalNs += tsAssertedElapsedNs;
-
-            const uint64_t avgAssertedUs = (pThis->Dbg.IRQ.tsAssertedTotalNs / pThis->Dbg.IRQ.cAsserted) / 1000;
-
-            if (avgAssertedUs > (1000 / HDA_TIMER_HZ) /* ms */ * 1000) /* Exceeds time slot? */
-                Log3Func(("Asserted (%s): %zuus elapsed (%zuus on average) -- %zuus alternation delay\n",
-                          pszSource, tsAssertedElapsedNs / 1000,
-                          avgAssertedUs,
-                          (pThis->Dbg.IRQ.tsDeassertedNs - pThis->Dbg.IRQ.tsAssertedNs) / 1000));
-#endif
-            Log3Func(("Asserted (%s): %RU64us between alternation (WALCLK=%RU64)\n",
-                      pszSource, tsLastElapsedNs / 1000, pThis->u64WalClk));
-
-            PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1 /* Assert */);
-            pThis->u8IRQL = 1;
-
-#ifdef DEBUG
-            pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS();
-            pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs;
-#endif
-        }
-    }
-    else
-    {
-        if (pThis->u8IRQL)
-        {
-#ifdef DEBUG
-            if (!pThis->Dbg.IRQ.tsProcessedLastNs)
-                pThis->Dbg.IRQ.tsProcessedLastNs = RTTimeNanoTS();
-
-            const uint64_t tsLastElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsProcessedLastNs;
-
-            if (!pThis->Dbg.IRQ.tsDeassertedNs)
-                pThis->Dbg.IRQ.tsDeassertedNs = RTTimeNanoTS();
-
-            const uint64_t tsDeassertedElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsDeassertedNs;
-
-            pThis->Dbg.IRQ.cDeasserted++;
-            pThis->Dbg.IRQ.tsDeassertedTotalNs += tsDeassertedElapsedNs;
-
-            const uint64_t avgDeassertedUs = (pThis->Dbg.IRQ.tsDeassertedTotalNs / pThis->Dbg.IRQ.cDeasserted) / 1000;
-
-            if (avgDeassertedUs > (1000 / HDA_TIMER_HZ) /* ms */ * 1000) /* Exceeds time slot? */
-                Log3Func(("Deasserted (%s): %zuus elapsed (%zuus on average)\n",
-                          pszSource, tsDeassertedElapsedNs / 1000, avgDeassertedUs));
-
-            Log3Func(("Deasserted (%s): %RU64us between alternation (WALCLK=%RU64)\n",
-                      pszSource, tsLastElapsedNs / 1000, pThis->u64WalClk));
-#endif
-            PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0 /* Deassert */);
-            pThis->u8IRQL = 0;
-
-#ifdef DEBUG
-            pThis->Dbg.IRQ.tsDeassertedNs    = RTTimeNanoTS();
-            pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsDeassertedNs;
-#endif
-        }
-    }
-
-    return VINF_SUCCESS;
-}
-
-#ifdef IN_RING3
 /**
  * Reschedules pending interrupts for all audio streams which have complete
@@ -1878,271 +767,4 @@
     return rc;
 }
-
-/**
- * Creates an HDA stream.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to create.
- * @param   pThis               HDA state to assign the HDA stream to.
- */
-static int hdaStreamCreate(PHDASTREAM pStream, PHDASTATE pThis)
-{
-    RT_NOREF(pThis);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    pStream->u8SD           = UINT8_MAX;
-    pStream->pMixSink       = NULL;
-    pStream->pHDAState      = pThis;
-
-    pStream->State.fInReset = false;
-#ifdef HDA_USE_DMA_ACCESS_HANDLER
-    RTListInit(&pStream->State.lstDMAHandlers);
-#endif
-
-    int rc = RTCircBufCreate(&pStream->State.pCircBuf, _64K); /** @todo Make this configurable. */
-    if (RT_SUCCESS(rc))
-    {
-        rc = hdaStreamPeriodCreate(&pStream->State.Period);
-        if (RT_SUCCESS(rc))
-            rc = RTCritSectInit(&pStream->State.CritSect);
-    }
-
-#ifdef DEBUG
-    int rc2 = RTCritSectInit(&pStream->Dbg.CritSect);
-    AssertRC(rc2);
-#endif
-
-    return rc;
-}
-
-/**
- * Destroys an HDA stream.
- *
- * @param   pStream             HDA stream to destroy.
- */
-static void hdaStreamDestroy(PHDASTREAM pStream)
-{
-    AssertPtrReturnVoid(pStream);
-
-    LogFlowFunc(("[SD%RU8]: Destroying ...\n", pStream->u8SD));
-
-    hdaStreamMapDestroy(&pStream->State.Mapping);
-
-    int rc2;
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    rc2 = hdaStreamAsyncIODestroy(pStream);
-    AssertRC(rc2);
-#else
-    RT_NOREF(pThis);
-#endif
-
-    rc2 = RTCritSectDelete(&pStream->State.CritSect);
-    AssertRC(rc2);
-
-    if (pStream->State.pCircBuf)
-    {
-        RTCircBufDestroy(pStream->State.pCircBuf);
-        pStream->State.pCircBuf = NULL;
-    }
-
-    hdaStreamPeriodDestroy(&pStream->State.Period);
-
-#ifdef DEBUG
-    rc2 = RTCritSectDelete(&pStream->Dbg.CritSect);
-    AssertRC(rc2);
-#endif
-
-    LogFlowFuncLeave();
-}
-
-/**
- * Initializes an HDA stream.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to initialize.
- * @param   uSD                 SD (stream descriptor) number to assign the HDA stream to.
- */
-static int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    PHDASTATE pThis = pStream->pHDAState;
-    AssertPtr(pThis);
-
-    pStream->u8SD       = uSD;
-    pStream->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStream->u8SD),
-                                      HDA_STREAM_REG(pThis, BDPU, pStream->u8SD));
-    pStream->u16LVI     = HDA_STREAM_REG(pThis, LVI, pStream->u8SD);
-    pStream->u32CBL     = HDA_STREAM_REG(pThis, CBL, pStream->u8SD);
-    pStream->u16FIFOS   = HDA_STREAM_REG(pThis, FIFOS, pStream->u8SD) + 1;
-
-    /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
-    hdaStreamUpdateLPIB(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
-
-    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg;
-
-    int rc = hdaSDFMTToPCMProps(HDA_STREAM_REG(pThis, FMT, uSD), &pCfg->Props);
-    if (RT_FAILURE(rc))
-    {
-        LogRel(("HDA: Warning: Format 0x%x for stream #%RU8 not supported\n", HDA_STREAM_REG(pThis, FMT, uSD), uSD));
-        return rc;
-    }
-
-    /* Set the stream's direction. */
-    pCfg->enmDir = hdaGetDirFromSD(pStream->u8SD);
-
-    /* The the stream's name, based on the direction. */
-    switch (pCfg->enmDir)
-    {
-        case PDMAUDIODIR_IN:
-# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
-#  error "Implement me!"
-# else
-            pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;
-            pCfg->enmLayout         = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
-            RTStrCopy(pCfg->szName, sizeof(pCfg->szName), "Line In");
-# endif
-            break;
-
-        case PDMAUDIODIR_OUT:
-            /* Destination(s) will be set in hdaAddStreamOut(),
-             * based on the channels / stream layout. */
-            break;
-
-        default:
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    /*
-     * Initialize the stream mapping in any case, regardless if
-     * we support surround audio or not. This is needed to handle
-     * the supported channels within a single audio stream, e.g. mono/stereo.
-     *
-     * In other words, the stream mapping *always* knows the real
-     * number of channels in a single audio stream.
-     */
-    rc = hdaStreamMapInit(&pStream->State.Mapping, &pCfg->Props);
-    AssertRCReturn(rc, rc);
-
-    LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16, rc=%Rrc\n",
-             pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS, rc));
-
-    return rc;
-}
-
-/**
- * Resets an HDA stream.
- *
- * @param   pThis               HDA state.
- * @param   pStream             HDA stream to reset.
- * @param   uSD                 Stream descriptor (SD) number to use for this stream.
- */
-static void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD)
-{
-    AssertPtrReturnVoid(pThis);
-    AssertPtrReturnVoid(pStream);
-    AssertReturnVoid(uSD < HDA_MAX_STREAMS);
-
-# ifdef VBOX_STRICT
-    AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_RUN),
-                     ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
-# endif
-
-    LogFunc(("[SD%RU8]: Reset\n", uSD));
-
-    /*
-     * Set reset state.
-     */
-    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false); /* No nested calls. */
-    ASMAtomicXchgBool(&pStream->State.fInReset, true);
-
-    /*
-     * Second, initialize the registers.
-     */
-    HDA_STREAM_REG(pThis, STS,   uSD) = HDA_SDSTS_FIFORDY;
-    /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
-     * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
-    HDA_STREAM_REG(pThis, CTL,   uSD) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_SRST);
-    /* ICH6 defines default values (120 bytes for input and 192 bytes for output descriptors) of FIFO size. 18.2.39. */
-    HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDIFIFO_120B : HDA_SDOFIFO_192B;
-    /* See 18.2.38: Always defaults to 0x4 (32 bytes). */
-    HDA_STREAM_REG(pThis, FIFOW, uSD) = HDA_SDFIFOW_32B;
-    HDA_STREAM_REG(pThis, LPIB,  uSD) = 0;
-    HDA_STREAM_REG(pThis, CBL,   uSD) = 0;
-    HDA_STREAM_REG(pThis, LVI,   uSD) = 0;
-    HDA_STREAM_REG(pThis, FMT,   uSD) = 0;
-    HDA_STREAM_REG(pThis, BDPU,  uSD) = 0;
-    HDA_STREAM_REG(pThis, BDPL,  uSD) = 0;
-
-#ifdef HDA_USE_DMA_ACCESS_HANDLER
-    hdaStreamUnregisterDMAHandlers(pThis, pStream);
-#endif
-
-    RT_ZERO(pStream->State.BDLE);
-    pStream->State.uCurBDLE = 0;
-
-    if (pStream->State.pCircBuf)
-        RTCircBufReset(pStream->State.pCircBuf);
-
-    /* Reset stream map. */
-    hdaStreamMapReset(&pStream->State.Mapping);
-
-    /* (Re-)initialize the stream with current values. */
-    int rc2 = hdaStreamInit(pStream, uSD);
-    AssertRC(rc2);
-
-    /* Reset the stream's period. */
-    hdaStreamPeriodReset(&pStream->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;
-#endif
-
-    /* Report that we're done resetting this stream. */
-    HDA_STREAM_REG(pThis, CTL,   uSD) = 0;
-
-    LogFunc(("[SD%RU8] Reset\n", uSD));
-
-    /* Exit reset mode. */
-    ASMAtomicXchgBool(&pStream->State.fInReset, false);
-}
-
-/**
- * Enables or disables an HDA audio stream.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to enable or disable.
- * @param   fEnable             Whether to enable or disble the stream.
- */
-static int hdaStreamEnable(PHDASTREAM pStream, bool fEnable)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    LogFunc(("[SD%RU8]: fEnable=%RTbool, pMixSink=%p\n", pStream->u8SD, fEnable, pStream->pMixSink));
-
-    int rc = VINF_SUCCESS;
-
-    if (pStream->pMixSink) /* Stream attached to a sink? */
-    {
-        AUDMIXSINKCMD enmCmd = fEnable
-                             ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-
-        /* First, enable or disable the stream and the stream's sink, if any. */
-        if (pStream->pMixSink->pMixSink)
-            rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
-    }
-
-    LogFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8SD, rc));
-    return rc;
-}
 #endif /* IN_RING3 */
 
@@ -2278,18 +900,4 @@
     *pu32Value = u32LPIB;
     return VINF_SUCCESS;
-}
-
-/**
- * Retrieves the currently set value for the wall clock.
- *
- * @return  IPRT status code.
- * @return  Currently set wall clock value.
- * @param   pThis               HDA state.
- *
- * @remark  Operation is atomic.
- */
-uint64_t hdaWalClkGetCurrent(PHDASTATE pThis)
-{
-    return ASMAtomicReadU64(&pThis->u64WalClk);
 }
 
@@ -2329,79 +937,4 @@
 
     return u64WalClkNew;
-}
-
-/**
- * Sets the actual WALCLK register to the specified wall clock value.
- * The specified wall clock value only will be set (unless fForce is set to true) if all
- * handled HDA streams have passed (in time) that value. This guarantees that the WALCLK
- * register stays in sync with all handled HDA streams.
- *
- * @return  true if the WALCLK register has been updated, false if not.
- * @param   pThis               HDA state.
- * @param   u64WalClk           Wall clock value to set WALCLK register to.
- * @param   fForce              Whether to force setting the wall clock value or not.
- */
-bool hdaWalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce)
-{
-    const bool     fFrontPassed       = hdaStreamPeriodHasPassedAbsWalClk (&hdaSinkGetStream(pThis, &pThis->SinkFront)->State.Period,
-                                                                           u64WalClk);
-    const uint64_t u64FrontAbsWalClk  = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkFront)->State.Period);
-#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-# error "Implement me!"
-#endif
-
-    const bool     fLineInPassed      = hdaStreamPeriodHasPassedAbsWalClk (&hdaSinkGetStream(pThis, &pThis->SinkLineIn)->State.Period, u64WalClk);
-    const uint64_t u64LineInAbsWalClk = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkLineIn)->State.Period);
-#ifdef VBOX_WITH_HDA_MIC_IN
-    const bool     fMicInPassed       = hdaStreamPeriodHasPassedAbsWalClk (&hdaSinkGetStream(pThis, &pThis->SinkMicIn)->State.Period,  u64WalClk);
-    const uint64_t u64MicInAbsWalClk  = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkMicIn)->State.Period);
-#endif
-
-#ifdef VBOX_STRICT
-    const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk);
-#endif
-          uint64_t u64WalClkSet = u64WalClk;
-
-    /* Only drive the WALCLK register forward if all (active) stream periods have passed
-     * the specified point in time given by u64WalClk. */
-    if (  (   fFrontPassed
-#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-# error "Implement me!"
-#endif
-           && fLineInPassed
-#ifdef VBOX_WITH_HDA_MIC_IN
-           && fMicInPassed
-#endif
-          )
-       || fForce)
-    {
-        if (!fForce)
-        {
-            /* Get the maximum value of all periods we need to handle.
-             * Not the most elegant solution, but works for now ... */
-            u64WalClk = RT_MAX(u64WalClkSet, u64FrontAbsWalClk);
-#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
-# error "Implement me!"
-#endif
-            u64WalClk = RT_MAX(u64WalClkSet, u64LineInAbsWalClk);
-#ifdef VBOX_WITH_HDA_MIC_IN
-            u64WalClk = RT_MAX(u64WalClkSet, u64MicInAbsWalClk);
-#endif
-            AssertMsg(u64WalClkSet > u64WalClkCur,
-                      ("Setting WALCLK to a stale or backward value (%RU64 -> %RU64) isn't a good idea really. "
-                       "Good luck with stuck audio stuff.\n", u64WalClkCur, u64WalClkSet));
-        }
-
-        /* Set the new WALCLK value. */
-        ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClkSet);
-    }
-
-    const uint64_t u64WalClkNew = hdaWalClkGetCurrent(pThis);
-
-    Log3Func(("Cur: %RU64, New: %RU64 (force %RTbool) -> %RU64 %s\n",
-              u64WalClkCur, u64WalClk, fForce,
-              u64WalClkNew, u64WalClkNew == u64WalClk ? "[OK]" : "[DELAYED]"));
-
-    return (u64WalClkNew == u64WalClk);
 }
 #endif /* IN_RING3 */
@@ -2859,87 +1392,4 @@
 
 #ifdef IN_RING3
-/**
- * Converts an HDA stream's SDFMT register into a given PCM properties structure.
- *
- * @return  IPRT status code.
- * @param   u32SDFMT            The HDA stream's SDFMT value to convert.
- * @param   pProps              PCM properties structure to hold converted result on success.
- */
-static int hdaSDFMTToPCMProps(uint32_t u32SDFMT, PPDMAUDIOPCMPROPS pProps)
-{
-    AssertPtrReturn(pProps, VERR_INVALID_POINTER);
-
-# define EXTRACT_VALUE(v, mask, shift) ((v & ((mask) << (shift))) >> (shift))
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t u32Hz     = EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BASE_RATE_MASK, HDA_SDFMT_BASE_RATE_SHIFT)
-                       ? 44100 : 48000;
-    uint32_t u32HzMult = 1;
-    uint32_t u32HzDiv  = 1;
-
-    switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_MULT_MASK, HDA_SDFMT_MULT_SHIFT))
-    {
-        case 0: u32HzMult = 1; break;
-        case 1: u32HzMult = 2; break;
-        case 2: u32HzMult = 3; break;
-        case 3: u32HzMult = 4; break;
-        default:
-            LogFunc(("Unsupported multiplier %x\n",
-                     EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_MULT_MASK, HDA_SDFMT_MULT_SHIFT)));
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-    switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_DIV_MASK, HDA_SDFMT_DIV_SHIFT))
-    {
-        case 0: u32HzDiv = 1; break;
-        case 1: u32HzDiv = 2; break;
-        case 2: u32HzDiv = 3; break;
-        case 3: u32HzDiv = 4; break;
-        case 4: u32HzDiv = 5; break;
-        case 5: u32HzDiv = 6; break;
-        case 6: u32HzDiv = 7; break;
-        case 7: u32HzDiv = 8; break;
-        default:
-            LogFunc(("Unsupported divisor %x\n",
-                     EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_DIV_MASK, HDA_SDFMT_DIV_SHIFT)));
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    uint8_t cBits = 0;
-    switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))
-    {
-        case 0:
-            cBits = 8;
-            break;
-        case 1:
-            cBits = 16;
-            break;
-        case 4:
-            cBits = 32;
-            break;
-        default:
-            AssertMsgFailed(("Unsupported bits per sample %x\n",
-                             EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)));
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        RT_BZERO(pProps, sizeof(PDMAUDIOPCMPROPS));
-
-        pProps->cBits     = cBits;
-        pProps->fSigned   = true;
-        pProps->cChannels = (u32SDFMT & 0xf) + 1;
-        pProps->uHz       = u32Hz * u32HzMult / u32HzDiv;
-        pProps->cShift    = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cBits, pProps->cChannels);
-    }
-
-# undef EXTRACT_VALUE
-    return rc;
-}
-
 /**
  * Adds an audio output stream to the device setup using the given configuration.
@@ -3395,175 +1845,4 @@
 #ifdef IN_RING3
 
-# ifdef HDA_USE_DMA_ACCESS_HANDLER
-/**
- * Registers access handlers for a stream's BDLE DMA accesses.
- *
- * @returns true if registration was successful, false if not.
- * @param   pStream             HDA stream to register BDLE access handlers for.
- */
-static bool hdaStreamRegisterDMAHandlers(PHDASTREAM pStream)
-{
-    /* At least LVI and the BDL base must be set. */
-    if (   !pStream->u16LVI
-        || !pStream->u64BDLBase)
-    {
-        return false;
-    }
-
-    hdaStreamUnregisterDMAHandlers(pStream);
-
-    LogFunc(("Registering ...\n"));
-
-    int rc = VINF_SUCCESS;
-
-    /*
-     * Create BDLE ranges.
-     */
-
-    struct BDLERANGE
-    {
-        RTGCPHYS uAddr;
-        uint32_t uSize;
-    } arrRanges[16]; /** @todo Use a define. */
-
-    size_t cRanges = 0;
-
-    for (uint16_t i = 0; i < pStream->u16LVI + 1; i++)
-    {
-        HDABDLE BDLE;
-        rc = hdaBDLEFetch(pThis, &BDLE, pStream->u64BDLBase, i /* Index */);
-        if (RT_FAILURE(rc))
-            break;
-
-        bool fAddRange = true;
-        BDLERANGE *pRange;
-
-        if (cRanges)
-        {
-            pRange = &arrRanges[cRanges - 1];
-
-            /* Is the current range a direct neighbor of the current BLDE? */
-            if ((pRange->uAddr + pRange->uSize) == BDLE.Desc.u64BufAdr)
-            {
-                /* Expand the current range by the current BDLE's size. */
-                pRange->uSize += BDLE.Desc.u32BufSize;
-
-                /* Adding a new range in this case is not needed anymore. */
-                fAddRange = false;
-
-                LogFunc(("Expanding range %zu by %RU32 (%RU32 total now)\n", cRanges - 1, BDLE.Desc.u32BufSize, pRange->uSize));
-            }
-        }
-
-        /* Do we need to add a new range? */
-        if (   fAddRange
-            && cRanges < RT_ELEMENTS(arrRanges))
-        {
-            pRange = &arrRanges[cRanges];
-
-            pRange->uAddr = BDLE.Desc.u64BufAdr;
-            pRange->uSize = BDLE.Desc.u32BufSize;
-
-            LogFunc(("Adding range %zu - 0x%x (%RU32)\n", cRanges, pRange->uAddr, pRange->uSize));
-
-            cRanges++;
-        }
-    }
-
-    LogFunc(("%zu ranges total\n", cRanges));
-
-    /*
-     * Register all ranges as DMA access handlers.
-     */
-
-    for (size_t i = 0; i < cRanges; i++)
-    {
-        BDLERANGE *pRange = &arrRanges[i];
-
-        PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)RTMemAllocZ(sizeof(HDADMAACCESSHANDLER));
-        if (!pHandler)
-        {
-            rc = VERR_NO_MEMORY;
-            break;
-        }
-
-        RTListAppend(&pStream->State.lstDMAHandlers, &pHandler->Node);
-
-        pHandler->pStream = pStream; /* Save a back reference to the owner. */
-
-        char szDesc[32];
-        RTStrPrintf(szDesc, sizeof(szDesc), "HDA[SD%RU8 - RANGE%02zu]", pStream->u8SD, i);
-
-        int rc2 = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3), PGMPHYSHANDLERKIND_WRITE,
-                                                   hdaDMAAccessHandler,
-                                                   NULL, NULL, NULL,
-                                                   NULL, NULL, NULL,
-                                                   szDesc, &pHandler->hAccessHandlerType);
-        AssertRCBreak(rc2);
-
-        pHandler->BDLEAddr  = pRange->uAddr;
-        pHandler->BDLESize  = pRange->uSize;
-
-        /* Get first and last pages of the BDLE range. */
-        RTGCPHYS pgFirst = pRange->uAddr & ~PAGE_OFFSET_MASK;
-        RTGCPHYS pgLast  = RT_ALIGN(pgFirst + pRange->uSize, PAGE_SIZE);
-
-        /* Calculate the region size (in pages). */
-        RTGCPHYS regionSize = RT_ALIGN(pgLast - pgFirst, PAGE_SIZE);
-
-        pHandler->GCPhysFirst = pgFirst;
-        pHandler->GCPhysLast  = pHandler->GCPhysFirst + (regionSize - 1);
-
-        LogFunc(("\tRegistering region '%s': 0x%x - 0x%x (region size: %zu)\n",
-                 szDesc, pHandler->GCPhysFirst, pHandler->GCPhysLast, regionSize));
-        LogFunc(("\tBDLE @ 0x%x - 0x%x (%RU32)\n",
-                 pHandler->BDLEAddr, pHandler->BDLEAddr + pHandler->BDLESize, pHandler->BDLESize));
-
-        rc2 = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),
-                                         pHandler->GCPhysFirst, pHandler->GCPhysLast,
-                                         pHandler->hAccessHandlerType, pHandler, NIL_RTR0PTR, NIL_RTRCPTR,
-                                         szDesc);
-        AssertRCBreak(rc2);
-
-        pHandler->fRegistered = true;
-    }
-
-    LogFunc(("Registration ended with rc=%Rrc\n", rc));
-
-    return RT_SUCCESS(rc);
-}
-
-/**
- * Unregisters access handlers of a stream's BDLEs.
- *
- * @param   pStream             HDA stream to unregister BDLE access handlers for.
- */
-static void hdaStreamUnregisterDMAHandlers(PHDASTREAM pStream)
-{
-    LogFunc(("\n"));
-
-    PHDADMAACCESSHANDLER pHandler, pHandlerNext;
-    RTListForEachSafe(&pStream->State.lstDMAHandlers, pHandler, pHandlerNext, HDADMAACCESSHANDLER, Node)
-    {
-        if (!pHandler->fRegistered) /* Handler not registered? Skip. */
-            continue;
-
-        LogFunc(("Unregistering 0x%x - 0x%x (%zu)\n",
-                 pHandler->GCPhysFirst, pHandler->GCPhysLast, pHandler->GCPhysLast - pHandler->GCPhysFirst));
-
-        int rc2 = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),
-                                               pHandler->GCPhysFirst);
-        AssertRC(rc2);
-
-        RTListNodeRemove(&pHandler->Node);
-
-        RTMemFree(pHandler);
-        pHandler = NULL;
-    }
-
-    Assert(RTListIsEmpty(&pStream->State.lstDMAHandlers));
-}
-# endif /* HDA_USE_DMA_ACCESS_HANDLER */
-
 #ifdef LOG_ENABLED
 static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
@@ -3602,102 +1881,4 @@
 }
 #endif /* LOG_ENABLED */
-
-/**
- * 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.
- */
-static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pBDLE,   VERR_INVALID_POINTER);
-    AssertReturn(u64BaseDMA, VERR_INVALID_PARAMETER);
-
-    if (!u64BaseDMA)
-    {
-        LogRel2(("HDA: Unable to fetch BDLE #%RU16 - no base DMA address set (yet)\n", u16Entry));
-        return VERR_NOT_FOUND;
-    }
-    /** @todo Compare u16Entry with LVI. */
-
-    int rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + (u16Entry * sizeof(HDABDLEDESC)),
-                               &pBDLE->Desc, sizeof(pBDLE->Desc));
-
-    if (RT_SUCCESS(rc))
-    {
-        /* Reset internal state. */
-        RT_ZERO(pBDLE->State);
-        pBDLE->State.u32BDLIndex = u16Entry;
-    }
-
-    Log3Func(("Entry #%d @ 0x%x: %R[bdle], rc=%Rrc\n", u16Entry, u64BaseDMA + (u16Entry * sizeof(HDABDLEDESC)), pBDLE, rc));
-
-
-    return VINF_SUCCESS;
-}
-
-/**
- * Returns the number of outstanding stream data bytes which need to be processed
- * by the DMA engine assigned to this stream.
- *
- * @return Number of bytes for the DMA engine to process.
- */
-DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStream)
-{
-    AssertPtrReturn(pThis, 0);
-    AssertPtrReturn(pStream, 0);
-
-    if (!RT_BOOL(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN))
-    {
-        AssertFailed(); /* Should never happen. */
-        return 0;
-    }
-
-    /* Determine how much for the current BDL entry we have left to transfer. */
-    PHDABDLE pBDLE  = &pStream->State.BDLE;
-    const uint32_t cbBDLE = RT_MIN(pBDLE->Desc.u32BufSize, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
-
-    /* Determine how much we (still) can stuff in the stream's internal FIFO.  */
-    const uint32_t cbCircBuf   = (uint32_t)RTCircBufFree(pStream->State.pCircBuf);
-
-    uint32_t cbToTransfer = cbBDLE;
-
-    /* Make sure that we don't transfer more than our FIFO can hold at the moment.
-     * As the host sets the overall pace it needs to process some of the FIFO data first before
-     * we can issue a new DMA data transfer. */
-    if (cbToTransfer > cbCircBuf)
-        cbToTransfer = cbCircBuf;
-
-    Log3Func(("[SD%RU8] LPIB=%RU32 CBL=%RU32 cbCircBuf=%RU32, -> cbToTransfer=%RU32 %R[bdle]\n", pStream->u8SD,
-              HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u32CBL, cbCircBuf, cbToTransfer, pBDLE));
-    return cbToTransfer;
-}
-
-/**
- * Increases the amount of transferred (audio) data of an HDA stream and
- * reports this as needed to the guest.
- *
- * @param  pStream              HDA stream to increase amount for.
- * @param  cbInc                Amount (in bytes) to increase.
- */
-DECLINLINE(void) hdaStreamTransferInc(PHDASTREAM pStream, uint32_t cbInc)
-{
-    AssertPtrReturnVoid(pStream);
-
-    if (!cbInc)
-        return;
-
-    const PHDASTATE pThis  = pStream->pHDAState;
-
-    const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-
-    Log3Func(("[SD%RU8] %RU32 + %RU32 -> %RU32, CBL=%RU32\n",
-              pStream->u8SD, u32LPIB, cbInc, u32LPIB + cbInc, pStream->u32CBL));
-
-    hdaStreamUpdateLPIB(pStream, u32LPIB + cbInc);
-}
 
 /**
@@ -4334,251 +2515,4 @@
 }
 #endif /* HDA_USE_DMA_ACCESS_HANDLER */
-
-/**
- * Reads DMA data from a given HDA output stream into its associated FIFO buffer.
- *
- * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   pStream             HDA output stream to read DMA data from.
- * @param   cbToRead            How much (in bytes) to read from DMA.
- * @param   pcbRead             Returns read bytes from DMA. Optional.
- */
-static int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbRead is optional. */
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbReadTotal = 0;
-
-    PHDABDLE   pBDLE     = &pStream->State.BDLE;
-    PRTCIRCBUF pCircBuf  = pStream->State.pCircBuf;
-    AssertPtr(pCircBuf);
-
-#ifdef HDA_DEBUG_SILENCE
-    uint64_t   csSilence = 0;
-
-    pStream->Dbg.cSilenceThreshold = 100;
-    pStream->Dbg.cbSilenceReadMin  = _1M;
-#endif
-
-    while (cbToRead)
-    {
-        /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
-        void *pvBuf;
-        size_t cbBuf;
-        RTCircBufAcquireWriteBlock(pCircBuf, RT_MIN(cbToRead, pStream->u16FIFOS), &pvBuf, &cbBuf);
-
-        if (cbBuf)
-        {
-            /*
-             * Read from the current BDLE's DMA buffer.
-             */
-            int rc2 = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
-                                        pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff + cbReadTotal, pvBuf, cbBuf);
-            AssertRC(rc2);
-
-#ifdef HDA_DEBUG_SILENCE
-            uint16_t *pu16Buf = (uint16_t *)pvBuf;
-            for (size_t i = 0; i < cbBuf / sizeof(uint16_t); i++)
-            {
-                if (*pu16Buf == 0)
-                {
-                    csSilence++;
-                }
-                else
-                    break;
-                pu16Buf++;
-            }
-#endif
-
-#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
-            if (cbBuf)
-            {
-                RTFILE fh;
-                rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMARead.pcm",
-                                 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-                if (RT_SUCCESS(rc2))
-                {
-                    RTFileWrite(fh, pvBuf, cbBuf, NULL);
-                    RTFileClose(fh);
-                }
-                else
-                    AssertRC(rc2);
-            }
-#endif
-
-#if 0
-            pStream->Dbg.cbReadTotal += cbBuf;
-            const uint64_t cbWritten = ASMAtomicReadU64(&pStream->Dbg.cbWrittenTotal);
-            Log3Func(("cbRead=%RU64, cbWritten=%RU64 -> %RU64 bytes %s\n",
-                      pStream->Dbg.cbReadTotal, cbWritten,
-                      pStream->Dbg.cbReadTotal >= cbWritten ? pStream->Dbg.cbReadTotal - cbWritten : cbWritten - pStream->Dbg.cbReadTotal,
-                      pStream->Dbg.cbReadTotal > cbWritten ? "too much" : "too little"));
-#endif
-
-#ifdef VBOX_WITH_STATISTICS
-            STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBuf);
-#endif
-        }
-
-        RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
-
-        if (!cbBuf)
-        {
-            rc = VERR_BUFFER_OVERFLOW;
-            break;
-        }
-
-        cbReadTotal += (uint32_t)cbBuf;
-        Assert(pBDLE->State.u32BufOff + cbReadTotal <= pBDLE->Desc.u32BufSize);
-
-        Assert(cbToRead >= cbBuf);
-        cbToRead    -= (uint32_t)cbBuf;
-    }
-
-#ifdef HDA_DEBUG_SILENCE
-
-    if (csSilence)
-        pStream->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;
-    }
-#endif
-
-    if (RT_SUCCESS(rc))
-    {
-        if (pcbRead)
-            *pcbRead = cbReadTotal;
-    }
-
-    return rc;
-}
-
-/**
- * Tells whether a given BDLE is complete or not.
- *
- * @return  true if BDLE is complete, false if not.
- * @param   pBDLE               BDLE to retrieve status for.
- */
-static bool hdaBDLEIsComplete(PHDABDLE pBDLE)
-{
-    bool fIsComplete = false;
-
-    if (   !pBDLE->Desc.u32BufSize /* There can be BDLEs with 0 size. */
-        || (pBDLE->State.u32BufOff >= pBDLE->Desc.u32BufSize))
-    {
-        Assert(pBDLE->State.u32BufOff == pBDLE->Desc.u32BufSize);
-        fIsComplete = true;
-    }
-
-    Log3Func(("%R[bdle] => %s\n", pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE"));
-
-    return fIsComplete;
-}
-
-
-/**
- * Tells whether a given BDLE needs an interrupt or not.
- *
- * @return  true if BDLE needs an interrupt, false if not.
- * @param   pBDLE               BDLE to retrieve status for.
- */
-static bool hdaBDLENeedsInterrupt(PHDABDLE pBDLE)
-{
-    return (pBDLE->Desc.fFlags & HDA_BDLE_FLAG_IOC);
-}
-
-/**
- * Writes audio data from an HDA input stream's FIFO to its associated DMA area.
- *
- * @return  IPRT status code.
- * @param   pThis               HDA state.
- * @param   pStream             HDA input stream to write audio data to.
- * @param   cbToWrite           How much (in bytes) to write.
- * @param   pcbWritten          Returns written bytes on success. Optional.
- */
-static int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbWritten is optional. */
-
-    PHDABDLE   pBDLE    = &pStream->State.BDLE;
-    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
-    AssertPtr(pCircBuf);
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbWrittenTotal = 0;
-
-    void *pvBuf  = NULL;
-    size_t cbBuf = 0;
-
-    uint8_t abSilence[HDA_FIFO_MAX + 1] = { 0 };
-
-    while (cbToWrite)
-    {
-        size_t cbChunk = RT_MIN(cbToWrite, pStream->u16FIFOS);
-
-        size_t cbBlock = 0;
-        RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvBuf, &cbBlock);
-
-        if (cbBlock)
-        {
-            cbBuf = cbBlock;
-        }
-        else /* No audio data available? Send silence. */
-        {
-            pvBuf = &abSilence;
-            cbBuf = cbChunk;
-        }
-
-        /* Sanity checks. */
-        Assert(cbBuf <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
-        Assert(cbBuf % HDA_FRAME_SIZE == 0);
-        Assert((cbBuf >> 1) >= 1);
-
-#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
-        RTFILE fh;
-        RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAWrite.pcm",
-                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-        RTFileWrite(fh, pvBuf, cbBuf, NULL);
-        RTFileClose(fh);
-#endif
-        int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
-                                        pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff + cbWrittenTotal,
-                                        pvBuf, cbBuf);
-        AssertRC(rc2);
-
-#ifdef VBOX_WITH_STATISTICS
-        STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbBuf);
-#endif
-        if (cbBlock)
-            RTCircBufReleaseReadBlock(pCircBuf, cbBlock);
-
-        Assert(cbToWrite >= cbBuf);
-        cbToWrite -= (uint32_t)cbBuf;
-
-        cbWrittenTotal += (uint32_t)cbBuf;
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (pcbWritten)
-            *pcbWritten = cbWrittenTotal;
-    }
-    else
-        LogFunc(("Failed with %Rrc\n", rc));
-
-    return rc;
-}
 
 /**
@@ -4789,760 +2723,4 @@
 #endif
 
-/**
- * Retrieves the available size of (buffered) audio data (in bytes) of a given HDA stream.
- *
- * @returns Available data (in bytes).
- * @param   pStream             HDA stream to retrieve size for.
- */
-static uint32_t hdaStreamGetUsed(PHDASTREAM pStream)
-{
-    AssertPtrReturn(pStream, 0);
-
-    if (!pStream->State.pCircBuf)
-        return 0;
-
-    return (uint32_t)RTCircBufUsed(pStream->State.pCircBuf);
-}
-
-/**
- * Retrieves the free size of audio data (in bytes) of a given HDA stream.
- *
- * @returns Free data (in bytes).
- * @param   pStream             HDA stream to retrieve size for.
- */
-static uint32_t hdaStreamGetFree(PHDASTREAM pStream)
-{
-    AssertPtrReturn(pStream, 0);
-
-    if (!pStream->State.pCircBuf)
-        return 0;
-
-    return (uint32_t)RTCircBufFree(pStream->State.pCircBuf);
-}
-
-
-/**
- * Writes audio data from a mixer sink into an HDA stream's DMA buffer.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to write to.
- * @param   cbToWrite           Number of bytes to write.
- * @param   pcbWritten          Number of bytes written. Optional.
- */
-static int hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
-{
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
-    /* pcbWritten is optional. */
-
-    PHDAMIXERSINK pSink = pStream->pMixSink;
-    if (!pSink)
-    {
-        AssertMsgFailed(("[SD%RU8]: Can't write to a stream with no sink attached\n", pStream->u8SD));
-
-        if (pcbWritten)
-            *pcbWritten = 0;
-        return VINF_SUCCESS;
-    }
-
-    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
-    AssertPtr(pCircBuf);
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbWrittenTotal = 0;
-    uint32_t cbLeft         = RT_MIN(cbToWrite, (uint32_t)RTCircBufFree(pCircBuf));
-
-    while (cbLeft)
-    {
-        void *pvDst;
-        size_t cbDst;
-
-        uint32_t cbRead = 0;
-
-        RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst);
-
-        if (cbDst)
-        {
-            rc = AudioMixerSinkRead(pSink->pMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead);
-            AssertRC(rc);
-
-            Assert(cbDst >= cbRead);
-            Log2Func(("[SD%RU8]: %zu/%zu bytes read\n", pStream->u8SD, cbRead, cbDst));
-
-#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
-            RTFILE fh;
-            RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaStreamWrite.pcm",
-                       RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-            RTFileWrite(fh, pvDst, cbRead, NULL);
-            RTFileClose(fh);
-#endif
-        }
-
-        RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
-
-        if (RT_FAILURE(rc))
-            break;
-
-        Assert(cbLeft  >= cbRead);
-        cbLeft         -= cbRead;
-
-        cbWrittenTotal += cbRead;
-    }
-
-    if (pcbWritten)
-        *pcbWritten = cbWrittenTotal;
-
-    return rc;
-}
-
-
-/**
- * Reads audio data from an HDA stream's DMA buffer and writes into a specified mixer sink.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to read audio data from.
- * @param   cbToRead            Number of bytes to read.
- * @param   pcbRead             Number of bytes read. Optional.
- */
-static int hdaStreamRead(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;
-    AssertPtr(pCircBuf);
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbReadTotal = 0;
-    uint32_t cbLeft      = RT_MIN(cbToRead, (uint32_t)RTCircBufUsed(pCircBuf));
-
-    while (cbLeft)
-    {
-        void *pvSrc;
-        size_t cbSrc;
-
-        uint32_t cbWritten = 0;
-
-        RTCircBufAcquireReadBlock(pCircBuf, cbLeft, &pvSrc, &cbSrc);
-
-        if (cbSrc)
-        {
-#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
-            RTFILE fh;
-            RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaStreamRead.pcm",
-                       RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-            RTFileWrite(fh, pvSrc, cbSrc, NULL);
-            RTFileClose(fh);
-#endif
-            rc = AudioMixerSinkWrite(pSink->pMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten);
-            AssertRC(rc);
-
-            Assert(cbSrc >= cbWritten);
-            Log2Func(("[SD%RU8]: %zu/%zu bytes read\n", pStream->u8SD, cbWritten, cbSrc));
-        }
-
-        RTCircBufReleaseReadBlock(pCircBuf, cbWritten);
-
-        if (RT_FAILURE(rc))
-            break;
-
-        Assert(cbLeft  >= cbWritten);
-        cbLeft         -= cbWritten;
-
-        cbReadTotal    += cbWritten;
-    }
-
-    if (pcbRead)
-        *pcbRead = cbReadTotal;
-
-    return rc;
-}
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-/**
- * 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.
- */
-static DECLCALLBACK(int) hdaStreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
-{
-    PHDASTREAMTHREADCTX pCtx = (PHDASTREAMTHREADCTX)pvUser;
-    AssertPtr(pCtx);
-
-    PHDASTREAM pStream = pCtx->pStream;
-    AssertPtr(pStream);
-
-    PHDASTREAMSTATEAIO pAIO = &pCtx->pStream->State.AIO;
-
-    ASMAtomicXchgBool(&pAIO->fStarted, true);
-
-    RTThreadUserSignal(hThreadSelf);
-
-    LogFunc(("[SD%RU8]: Started\n", pStream->u8SD));
-
-    for (;;)
-    {
-        int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT);
-        if (RT_FAILURE(rc2))
-            break;
-
-        if (ASMAtomicReadBool(&pAIO->fShutdown))
-            break;
-
-        rc2 = RTCritSectEnter(&pAIO->CritSect);
-        if (RT_SUCCESS(rc2))
-        {
-            if (!pAIO->fEnabled)
-            {
-                RTCritSectLeave(&pAIO->CritSect);
-                continue;
-            }
-
-            hdaStreamUpdate(pStream, false /* fInTimer */);
-
-            int rc3 = RTCritSectLeave(&pAIO->CritSect);
-            AssertRC(rc3);
-        }
-
-        AssertRC(rc2);
-    }
-
-    LogFunc(("[SD%RU8]: Ended\n", pStream->u8SD));
-
-    ASMAtomicXchgBool(&pAIO->fStarted, false);
-
-    return VINF_SUCCESS;
-}
-
-/**
- * Creates the async I/O thread for a specific HDA audio stream.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA audio stream to create the async I/O thread for.
- */
-static int hdaStreamAsyncIOCreate(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
-
-    int rc;
-
-    if (!ASMAtomicReadBool(&pAIO->fStarted))
-    {
-        pAIO->fShutdown = false;
-
-        rc = RTSemEventCreate(&pAIO->Event);
-        if (RT_SUCCESS(rc))
-        {
-            rc = RTCritSectInit(&pAIO->CritSect);
-            if (RT_SUCCESS(rc))
-            {
-                HDASTREAMTHREADCTX Ctx = { pStream->pHDAState, pStream };
-
-                char szThreadName[64];
-                RTStrPrintf2(szThreadName, sizeof(szThreadName), "hdaAIO%RU8", pStream->u8SD);
-
-                rc = RTThreadCreate(&pAIO->Thread, hdaStreamAsyncIOThread, &Ctx,
-                                    0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, szThreadName);
-                if (RT_SUCCESS(rc))
-                    rc = RTThreadUserWait(pAIO->Thread, 10 * 1000 /* 10s timeout */);
-            }
-        }
-    }
-    else
-        rc = VINF_SUCCESS;
-
-    LogFunc(("[SD%RU8]: Returning %Rrc\n", pStream->u8SD, rc));
-    return rc;
-}
-
-/**
- * Destroys the async I/O thread of a specific HDA audio stream.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA audio stream to destroy the async I/O thread for.
- */
-static int hdaStreamAsyncIODestroy(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
-
-    if (!ASMAtomicReadBool(&pAIO->fStarted))
-        return VINF_SUCCESS;
-
-    ASMAtomicWriteBool(&pAIO->fShutdown, true);
-
-    int rc = hdaStreamAsyncIONotify(pStream);
-    AssertRC(rc);
-
-    int rcThread;
-    rc = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread);
-    LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc, rcThread));
-
-    if (RT_SUCCESS(rc))
-    {
-        rc = RTCritSectDelete(&pAIO->CritSect);
-        AssertRC(rc);
-
-        rc = RTSemEventDestroy(pAIO->Event);
-        AssertRC(rc);
-
-        pAIO->fStarted  = false;
-        pAIO->fShutdown = false;
-        pAIO->fEnabled  = false;
-    }
-
-    LogFunc(("[SD%RU8]: Returning %Rrc\n", pStream->u8SD, rc));
-    return rc;
-}
-
-/**
- * Lets the stream's async I/O thread know that there is some data to process.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to notify async I/O thread for.
- */
-static int hdaStreamAsyncIONotify(PHDASTREAM pStream)
-{
-    return RTSemEventSignal(pStream->State.AIO.Event);
-}
-
-/**
- * Locks the async I/O thread of a specific HDA audio stream.
- *
- * @param   pStream             HDA stream to lock async I/O thread for.
- */
-static void hdaStreamAsyncIOLock(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
-
-    if (!ASMAtomicReadBool(&pAIO->fStarted))
-        return;
-
-    int rc2 = RTCritSectEnter(&pAIO->CritSect);
-    AssertRC(rc2);
-}
-
-/**
- * Unlocks the async I/O thread of a specific HDA audio stream.
- *
- * @param   pStream             HDA stream to unlock async I/O thread for.
- */
-static void hdaStreamAsyncIOUnlock(PHDASTREAM pStream)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
-
-    if (!ASMAtomicReadBool(&pAIO->fStarted))
-        return;
-
-    int rc2 = RTCritSectLeave(&pAIO->CritSect);
-    AssertRC(rc2);
-}
-
-/**
- * Enables (resumes) or disables (pauses) the async I/O thread.
- *
- * @param   pStream             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.
- */
-static void hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable)
-{
-    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
-    ASMAtomicXchgBool(&pAIO->fEnabled, fEnable);
-}
-#endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */
-
-static uint32_t hdaStreamTransferGetElapsed(PHDASTREAM pStream)
-{
-    AssertPtr(pStream->pHDAState->pTimer);
-    const uint64_t cTicksNow     = TMTimerGet(pStream->pHDAState->pTimer);
-    const uint64_t cTicksPerSec  = TMTimerGetFreq(pStream->pHDAState->pTimer);
-
-    const uint64_t cTicksElapsed = cTicksNow - pStream->State.uTimerTS;
-#ifdef DEBUG
-    const uint64_t cMsElapsed    = cTicksElapsed / (cTicksPerSec / 1000);
-#endif
-
-    AssertPtr(pStream->pHDAState->pCodec);
-
-    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg;
-
-    /* A stream *always* runs with 48 kHz device-wise, regardless of the actual stream input/output format (Hz) being set. */
-    uint32_t csPerPeriod = (int)((pCfg->Props.cChannels * cTicksElapsed * 48000 /* Hz */ + cTicksPerSec) / cTicksPerSec / 2);
-    uint32_t cbPerPeriod = csPerPeriod << pCfg->Props.cShift;
-
-    Log3Func(("[SD%RU8] %RU64ms (%zu samples, %zu bytes) elapsed\n", pStream->u8SD, cMsElapsed, csPerPeriod, cbPerPeriod));
-
-    return cbPerPeriod;
-}
-
-/**
- * Transfers data of an HDA stream according to its usage (input / output).
- *
- * For an SDO (output) stream this means reading DMA data from the device to
- * the HDA stream's internal FIFO buffer.
- *
- * For an SDI (input) stream this is reading audio data from the HDA stream's
- * internal FIFO buffer and writing it as DMA data to the device.
- *
- * @returns IPRT status code.
- * @param   pStream             HDA stream to update.
- * @param   cbToProcessMax      Maximum of data (in bytes) to process.
- */
-static int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
-{
-    AssertPtrReturn(pStream,        VERR_INVALID_POINTER);
-    AssertReturn(cbToProcessMax,    VERR_INVALID_PARAMETER);
-
-    hdaStreamLock(pStream);
-
-    PHDASTATE pThis = pStream->pHDAState;
-    AssertPtr(pThis);
-
-    PHDASTREAMPERIOD pPeriod = &pStream->State.Period;
-    int rc = hdaStreamPeriodLock(pPeriod);
-    AssertRC(rc);
-
-    bool fProceed = true;
-
-    /* Stream not running? */
-    if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN))
-    {
-        Log3Func(("[SD%RU8] RUN bit not set\n", pStream->u8SD));
-        fProceed = false;
-    }
-    /* Period complete? */
-    else if (hdaStreamPeriodIsComplete(pPeriod))
-    {
-        Log3Func(("[SD%RU8] Period is complete, nothing to do\n", pStream->u8SD));
-        fProceed = false;
-    }
-
-    if (!fProceed)
-    {
-        hdaStreamPeriodUnlock(pPeriod);
-        hdaStreamUnlock(pStream);
-        return VINF_SUCCESS;
-    }
-
-    /* Sanity checks. */
-    Assert(pStream->u8SD < HDA_MAX_STREAMS);
-    Assert(pStream->u64BDLBase);
-    Assert(pStream->u32CBL);
-
-    /* State sanity checks. */
-    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false);
-
-    /* Fetch first / next BDL entry. */
-    PHDABDLE pBDLE = &pStream->State.BDLE;
-    if (hdaBDLEIsComplete(pBDLE))
-    {
-        rc = hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
-        AssertRC(rc);
-    }
-
-    const uint32_t cbPeriodRemaining = hdaStreamPeriodGetRemainingFrames(pPeriod) * HDA_FRAME_SIZE;
-    Assert(cbPeriodRemaining); /* Paranoia. */
-
-    const uint32_t cbElapsed         = hdaStreamTransferGetElapsed(pStream);
-    Assert(cbElapsed);         /* Paranoia. */
-
-    /* Limit the data to read, as this routine could be delayed and therefore
-     * report wrong (e.g. too much) cbElapsed bytes. */
-    uint32_t cbLeft                  = RT_MIN(RT_MIN(cbPeriodRemaining, cbElapsed), cbToProcessMax);
-
-    Log3Func(("[SD%RU8] cbPeriodRemaining=%RU32, cbElapsed=%RU32, cbToProcessMax=%RU32 -> cbLeft=%RU32\n",
-              pStream->u8SD, cbPeriodRemaining, cbElapsed, cbToProcessMax, cbLeft));
-
-    Assert(cbLeft % HDA_FRAME_SIZE == 0); /* Paranoia. */
-
-    while (cbLeft)
-    {
-        uint32_t cbChunk = RT_MIN(hdaStreamGetTransferSize(pThis, pStream), cbLeft);
-        if (!cbChunk)
-            break;
-
-        uint32_t cbDMA   = 0;
-
-        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
-        {
-            STAM_PROFILE_START(&pThis->StatOut, a);
-
-            rc = hdaDMARead(pThis, pStream, cbChunk, &cbDMA /* pcbRead */);
-            if (RT_FAILURE(rc))
-                LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
-
-            STAM_PROFILE_STOP(&pThis->StatOut, a);
-        }
-        else if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) /* Input (SDI). */
-        {
-            STAM_PROFILE_START(&pThis->StatIn, a);
-
-            rc = hdaDMAWrite(pThis, pStream, cbChunk, &cbDMA /* pcbWritten */);
-            if (RT_FAILURE(rc))
-                LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
-
-            STAM_PROFILE_STOP(&pThis->StatIn, a);
-        }
-        else /** @todo Handle duplex streams? */
-            AssertFailed();
-
-        if (cbDMA)
-        {
-            Assert(cbDMA % HDA_FRAME_SIZE == 0);
-
-            /* We always increment the position of DMA buffer counter because we're always reading
-             * into an intermediate buffer. */
-            pBDLE->State.u32BufOff += (uint32_t)cbDMA;
-            Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize);
-
-            hdaStreamTransferInc(pStream, cbDMA);
-
-            uint32_t framesDMA = cbDMA / HDA_FRAME_SIZE;
-
-            /* Add the transferred frames to the period. */
-            hdaStreamPeriodInc(pPeriod, framesDMA);
-
-            /* Save the timestamp of when the last successful DMA transfer has been for this stream. */
-            pStream->State.uTimerTS = TMTimerGet(pThis->pTimer);
-
-            Assert(cbLeft >= cbDMA);
-            cbLeft        -= cbDMA;
-        }
-
-        if (hdaBDLEIsComplete(pBDLE))
-        {
-            Log3Func(("[SD%RU8] Complete: %R[bdle]\n", pStream->u8SD, pBDLE));
-
-            if (hdaBDLENeedsInterrupt(pBDLE))
-            {
-                /* 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)
-                    hdaStreamPeriodAcquireInterrupt(pPeriod);
-            }
-
-            if (pStream->State.uCurBDLE == pStream->u16LVI)
-            {
-                Assert(pStream->u32CBL == HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
-
-                pStream->State.uCurBDLE = 0;
-                hdaStreamUpdateLPIB(pStream, 0 /* LPIB */);
-            }
-            else
-                pStream->State.uCurBDLE++;
-
-            hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
-
-            Log3Func(("[SD%RU8] Fetching: %R[bdle]\n", pStream->u8SD, pBDLE));
-        }
-
-        if (RT_FAILURE(rc))
-            break;
-    }
-
-    if (hdaStreamPeriodIsComplete(pPeriod))
-    {
-        Log3Func(("[SD%RU8] Period complete -- Current: %R[bdle]\n", pStream->u8SD, &pStream->State.BDLE));
-
-        /* Set the stream's BCIS bit.
-         *
-         * Note: This only must be done if the whole period is complete, and not if only
-         * one specific BDL entry is complete (if it has the IOC bit set).
-         *
-         * This will otherwise confuses the guest when it 1) deasserts the interrupt,
-         * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value.
-         *
-         * snd_hda_intel on Linux will tell. */
-        HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_SDSTS_BCIS;
-
-        /* Try updating the wall clock. */
-        const uint64_t u64WalClk  = hdaStreamPeriodGetAbsElapsedWalClk(pPeriod);
-        const bool     fWalClkSet = hdaWalClkSet(pThis, u64WalClk, false /* fForce */);
-
-        /* Does the period have any interrupts outstanding? */
-        if (hdaStreamPeriodNeedsInterrupt(pPeriod))
-        {
-            if (fWalClkSet)
-            {
-                Log3Func(("[SD%RU8] Set WALCLK to %RU64, triggering interrupt\n", pStream->u8SD, u64WalClk));
-
-                /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
-                 * ending / beginning a period. */
-#ifndef DEBUG
-                hdaProcessInterrupt(pThis);
-#else
-                hdaProcessInterrupt(pThis, __FUNCTION__);
-#endif
-            }
-        }
-        else
-        {
-            /* End the period first ... */
-            hdaStreamPeriodEnd(pPeriod);
-
-            /* ... and immediately begin the next one. */
-            hdaStreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis));
-        }
-    }
-
-    hdaStreamPeriodUnlock(pPeriod);
-
-    Log3Func(("[SD%RU8] Returning %Rrc ==========================================\n", pStream->u8SD, rc));
-
-    if (RT_FAILURE(rc))
-        LogFunc(("[SD%RU8] Failed with rc=%Rrcc\n", pStream->u8SD, rc));
-
-    hdaStreamUnlock(pStream);
-
-    return VINF_SUCCESS;
-}
-
-/**
- * Updates a HDA stream by doing its required data transfers.
- * The host sink(s) set the overall pace.
- *
- * This routine is called by both, the synchronous and the asynchronous, implementations.
- *
- * @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).
- */
-static void hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
-{
-    PAUDMIXSINK pSink = NULL;
-    if (   pStream->pMixSink
-        && pStream->pMixSink->pMixSink)
-    {
-        pSink = pStream->pMixSink->pMixSink;
-    }
-
-    if (!AudioMixerSinkIsActive(pSink)) /* No sink available? Bail out. */
-        return;
-
-    int rc2;
-
-    if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
-    {
-        /* Is the HDA stream ready to be written (guest output data) to? If so, by how much? */
-        const uint32_t cbFree = hdaStreamGetFree(pStream);
-
-        if (   fInTimer
-            && cbFree)
-        {
-            Log3Func(("[SD%RU8] cbFree=%RU32\n", pStream->u8SD, cbFree));
-
-            /* Do the DMA transfer. */
-            rc2 = hdaStreamTransfer(pStream, cbFree);
-            AssertRC(rc2);
-        }
-
-        /* How much (guest output) data is available at the moment for the HDA stream? */
-        uint32_t cbUsed = hdaStreamGetUsed(pStream);
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        if (   fInTimer
-            && cbUsed)
-        {
-            rc2 = hdaStreamAsyncIONotify(pStream);
-            AssertRC(rc2);
-        }
-        else
-        {
-#endif
-            const uint32_t cbSinkWritable = AudioMixerSinkGetWritable(pSink);
-
-            /* Do not write more than the sink can hold at the moment.
-             * The host sets the overall pace. */
-            if (cbUsed > cbSinkWritable)
-                cbUsed = cbSinkWritable;
-
-            if (cbUsed)
-            {
-                /* Read (guest output) data and write it to the stream's sink. */
-                rc2 = hdaStreamRead(pStream, cbUsed, NULL /* pcbRead */);
-                AssertRC(rc2);
-            }
-
-            /* When running synchronously, update the associated sink here.
-             * Otherwise this will be done in the device timer. */
-            rc2 = AudioMixerSinkUpdate(pSink);
-            AssertRC(rc2);
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        }
-#endif
-    }
-    else /* Input (SDI). */
-    {
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        if (fInTimer)
-        {
-            rc2 = hdaStreamAsyncIONotify(pStream);
-            AssertRC(rc2);
-        }
-        else
-        {
-#endif
-            rc2 = AudioMixerSinkUpdate(pSink);
-            AssertRC(rc2);
-
-            /* Is the sink ready to be read (host input data) from? If so, by how much? */
-            const uint32_t cbReadable = AudioMixerSinkGetReadable(pSink);
-
-            /* How much (guest input) data is free at the moment? */
-            uint32_t cbFree = hdaStreamGetFree(pStream);
-
-            Log3Func(("[SD%RU8] cbReadable=%RU32, cbFree=%RU32\n", pStream->u8SD, cbReadable, cbFree));
-
-            /* Do not read more than the sink can provide at the moment.
-             * The host sets the overall pace. */
-            if (cbFree > cbReadable)
-                cbFree = cbReadable;
-
-            if (cbFree)
-            {
-                /* Write (guest input) data to the stream which was read from stream's sink before. */
-                rc2 = hdaStreamWrite(pStream, cbFree, NULL /* pcbWritten */);
-                AssertRC(rc2);
-            }
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        }
-#endif
-
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        if (fInTimer)
-        {
-#endif
-            const uint32_t cbToTransfer = hdaStreamGetUsed(pStream);
-            if (cbToTransfer)
-            {
-                /* When running synchronously, do the DMA data transfers here.
-                 * Otherwise this will be done in the stream's async I/O thread. */
-                rc2 = hdaStreamTransfer(pStream, cbToTransfer);
-                AssertRC(rc2);
-            }
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-        }
-#endif
-    }
-}
 #endif /* IN_RING3 */
 
Index: /trunk/src/VBox/Devices/Audio/DevHDA.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.h	(revision 67899)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.h	(revision 67899)
@@ -0,0 +1,216 @@
+/* $Id$ */
+/** @file
+ * DevHDA.h - VBox Intel HD Audio Controller.
+ */
+
+/*
+ * Copyright (C) 2016-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef DEV_HDA_H
+#define DEV_HDA_H
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <VBox/vmm/pdmdev.h>
+
+#include "AudioMixer.h"
+
+#include "HDACodec.h"
+#include "HDAStream.h"
+#include "HDAStreamMap.h"
+#include "HDAStreamPeriod.h"
+
+
+/*********************************************************************************************************************************
+*   Defines                                                                                                                      *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+/**
+ * Structure defining an HDA mixer sink.
+ * Its purpose is to know which audio mixer sink is bound to
+ * which SDn (SDI/SDO) device stream.
+ *
+ * This is needed in order to handle interleaved streams
+ * (that is, multiple channels in one stream) or non-interleaved
+ * streams (each channel has a dedicated stream).
+ *
+ * This is only known to the actual device emulation level.
+ */
+typedef struct HDAMIXERSINK
+{
+    /** SDn ID this sink is assigned to. 0 if not assigned. */
+    uint8_t                uSD;
+    /** Channel ID of SDn ID. Only valid if SDn ID is valid. */
+    uint8_t                uChannel;
+    uint8_t                Padding[3];
+    /** Pointer to the actual audio mixer sink. */
+    R3PTRTYPE(PAUDMIXSINK) pMixSink;
+} HDAMIXERSINK, *PHDAMIXERSINK;
+
+/**
+ * Structure for mapping a stream tag to an HDA stream.
+ */
+typedef struct HDATAG
+{
+    /** Own stream tag. */
+    uint8_t               uTag;
+    uint8_t               Padding[7];
+    /** Pointer to associated stream. */
+    R3PTRTYPE(PHDASTREAM) pStream;
+} HDATAG, *PHDATAG;
+
+#ifdef DEBUG
+/** @todo Make STAM values out of this? */
+typedef struct HDASTATEDBGINFO
+{
+    /** 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;
+} HDASTATEDBGINFO, *PHDASTATEDBGINFO;
+#endif
+
+/**
+ * ICH Intel HD Audio Controller state.
+ */
+typedef struct HDASTATE
+{
+    /** The PCI device structure. */
+    PDMPCIDEV                          PciDev;
+    /** R3 Pointer to the device instance. */
+    PPDMDEVINSR3                       pDevInsR3;
+    /** R0 Pointer to the device instance. */
+    PPDMDEVINSR0                       pDevInsR0;
+    /** R0 Pointer to the device instance. */
+    PPDMDEVINSRC                       pDevInsRC;
+    /** Padding for alignment. */
+    uint32_t                           u32Padding;
+    /** The base interface for LUN\#0. */
+    PDMIBASE                           IBase;
+    RTGCPHYS                           MMIOBaseAddr;
+    /** The HDA's register set. */
+    uint32_t                           au32Regs[HDA_NUM_REGS];
+    /** Internal stream states. */
+    HDASTREAM                          aStreams[HDA_MAX_STREAMS];
+    /** Mapping table between stream tags and stream states. */
+    HDATAG                             aTags[HDA_MAX_TAGS];
+    /** CORB buffer base address. */
+    uint64_t                           u64CORBBase;
+    /** RIRB buffer base address. */
+    uint64_t                           u64RIRBBase;
+    /** DMA base address.
+     *  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. */
+    uint32_t                           cbCorbBuf;
+    /** Padding for alignment. */
+    uint32_t                           u32Padding1;
+    /** Pointer to RIRB buffer. */
+    R3PTRTYPE(uint64_t *)              pu64RirbBuf;
+    /** Size in bytes of RIRB buffer. */
+    uint32_t                           cbRirbBuf;
+    /** DMA position buffer enable bit. */
+    bool                               fDMAPosition;
+    /** Flag whether the R0 part is enabled. */
+    bool                               fR0Enabled;
+    /** Flag whether the RC part is enabled. */
+    bool                               fRCEnabled;
+    /** Number of active (running) SDn streams. */
+    uint8_t                            cStreamsActive;
+#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
+    /** The timer for pumping data thru the attached LUN drivers. */
+    PTMTIMERR3                         pTimer;
+    /** Flag indicating whether the timer is active or not. */
+    bool                               fTimerActive;
+    uint8_t                            u8Padding1[7];
+    /** Timer ticks per Hz. */
+    uint64_t                           cTimerTicks;
+    /** The current timer expire time (in timer ticks). */
+    uint64_t                           tsTimerExpire;
+#endif
+#ifdef VBOX_WITH_STATISTICS
+# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
+    STAMPROFILE                        StatTimer;
+# endif
+    STAMPROFILE                        StatIn;
+    STAMPROFILE                        StatOut;
+    STAMCOUNTER                        StatBytesRead;
+    STAMCOUNTER                        StatBytesWritten;
+#endif
+    /** 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 WALCLK counter. */
+    uint64_t                           u64WalClk;
+    /** Response Interrupt Count (RINTCNT). */
+    uint8_t                            u8RespIntCnt;
+    /** Current IRQ level. */
+    uint8_t                            u8IRQL;
+    /** Padding for alignment. */
+    uint8_t                            au8Padding2[6];
+#ifdef DEBUG
+    HDASTATEDBGINFO                    Dbg;
+#endif
+} HDASTATE, *PHDASTATE;
+
+#ifdef VBOX_WITH_AUDIO_HDA_CALLBACKS
+typedef struct HDACALLBACKCTX
+{
+    PHDASTATE  pThis;
+    PHDADRIVER pDriver;
+} HDACALLBACKCTX, *PHDACALLBACKCTX;
+#endif
+
+#endif /* DEV_HDA_H */
+
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 67898)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 67899)
@@ -1,9 +1,9 @@
 /* $Id$ */
 /** @file
- * DevHDACommon.h - Shared defines / functions between HDA controller and codec.
+ * DevHDACommon.h - Shared HDA device defines / functions.
  */
 
 /*
- * Copyright (C) 2016 Oracle Corporation
+ * Copyright (C) 2016-2017 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -18,4 +18,416 @@
 #ifndef DEV_HDA_COMMON_H
 #define DEV_HDA_COMMON_H
+
+#include "AudioMixer.h"
+
+/** See 302349 p 6.2. */
+typedef struct HDAREGDESC
+{
+    /** Register offset in the register space. */
+    uint32_t    offset;
+    /** Size in bytes. Registers of size > 4 are in fact tables. */
+    uint32_t    size;
+    /** Readable bits. */
+    uint32_t    readable;
+    /** Writable bits. */
+    uint32_t    writable;
+    /** Register descriptor (RD) flags of type HDA_RD_FLAG_.
+     *  These are used to specify the handling (read/write)
+     *  policy of the register. */
+    uint32_t    fFlags;
+    /** Read callback. */
+    int       (*pfnRead)(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
+    /** Write callback. */
+    int       (*pfnWrite)(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+    /** Index into the register storage array. */
+    uint32_t    mem_idx;
+    /** Abbreviated name. */
+    const char *abbrev;
+    /** Descripton. */
+    const char *desc;
+} HDAREGDESC, *PHDAREGDESC;
+
+/**
+ * HDA register aliases (HDA spec 3.3.45).
+ * @remarks Sorted by offReg.
+ */
+typedef struct HDAREGALIAS
+{
+    /** The alias register offset. */
+    uint32_t    offReg;
+    /** The register index. */
+    int         idxAlias;
+} HDAREGALIAS, *PHDAREGALIAS;
+
+/**
+ * At the moment we support 4 input + 4 output streams max, which is 8 in total.
+ * Bidirectional streams are currently *not* supported.
+ *
+ * Note: When changing any of those values, be prepared for some saved state
+ *       fixups / trouble!
+ */
+#define HDA_MAX_SDI                 4
+#define HDA_MAX_SDO                 4
+#define HDA_MAX_STREAMS             (HDA_MAX_SDI + HDA_MAX_SDO)
+
+/** Number of general registers. */
+#define HDA_NUM_GENERAL_REGS        34
+/** Number of total registers in the HDA's register map. */
+#define HDA_NUM_REGS                                       (HDA_NUM_GENERAL_REGS + (HDA_MAX_STREAMS * 10 /* Each stream descriptor has 10 registers */))
+/** Total number of stream tags (channels). Index 0 is reserved / invalid. */
+#define HDA_MAX_TAGS                16
+
+/*
+ * ICH6 datasheet defines limits for FIFOS registers (18.2.39)
+ * formula: size - 1
+ * Other values not listed are not supported.
+ */
+/** Maximum FIFO size (in bytes). */
+#define HDA_FIFO_MAX                256
+
+/** Default timer frequency (in Hz).
+ *
+ *  Note: Keep in mind that the Hz rate has nothing to do with samples rates
+ *        or DMA / interrupt timing -- it's purely needed in order to drive
+ *        the data flow at a constant (and sufficient) rate.
+ *
+ *        Lowering this value can ask for trouble, as backends then can run
+ *        into data underruns. */
+#define HDA_TIMER_HZ                200
+
+/** HDA's (fixed) audio frame size in bytes.
+ *  We only support 16-bit stereo frames at the moment. */
+#define HDA_FRAME_SIZE              4
+
+/** Offset of the SD0 register map. */
+#define HDA_REG_DESC_SD0_BASE       0x80
+
+/** Turn a short global register name into an memory index and a stringized name. */
+#define HDA_REG_IDX(abbrev)         HDA_MEM_IND_NAME(abbrev), #abbrev
+
+/** Turns a short stream register name into an memory index and a stringized name. */
+#define HDA_REG_IDX_STRM(reg, suff) HDA_MEM_IND_NAME(reg ## suff), #reg #suff
+
+/** Same as above for a register *not* stored in memory. */
+#define HDA_REG_IDX_NOMEM(abbrev)   0, #abbrev
+
+extern const HDAREGDESC g_aHdaRegMap[HDA_NUM_REGS];
+
+/**
+ * NB: Register values stored in memory (au32Regs[]) are indexed through
+ * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
+ * register descriptors in g_aHdaRegMap[] are indexed through the
+ * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
+ *
+ * The au32Regs[] layout is kept unchanged for saved state
+ * compatibility.
+ */
+
+/* Registers */
+#define HDA_REG_IND_NAME(x)         HDA_REG_##x
+#define HDA_MEM_IND_NAME(x)         HDA_RMX_##x
+#define HDA_REG_IND(pThis, x)       ((pThis)->au32Regs[g_aHdaRegMap[x].mem_idx])
+#define HDA_REG(pThis, x)           (HDA_REG_IND((pThis), HDA_REG_IND_NAME(x)))
+
+
+#define HDA_REG_GCAP                0 /* range 0x00-0x01*/
+#define HDA_RMX_GCAP                0
+/* GCAP HDASpec 3.3.2 This macro encodes the following information about HDA in a compact manner:
+ * oss (15:12) - number of output streams supported
+ * iss (11:8)  - number of input streams supported
+ * bss (7:3)   - number of bidirectional streams supported
+ * bds (2:1)   - number of serial data out (SDO) signals supported
+ * b64sup (0)  - 64 bit addressing supported.
+ */
+#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \
+    (  (((oss)   & 0xF)  << 12) \
+     | (((iss)   & 0xF)  << 8)  \
+     | (((bss)   & 0x1F) << 3)  \
+     | (((bds)   & 0x3)  << 2)  \
+     | ((b64sup) & 1))
+
+#define HDA_REG_VMIN                1 /* 0x02 */
+#define HDA_RMX_VMIN                1
+
+#define HDA_REG_VMAJ                2 /* 0x03 */
+#define HDA_RMX_VMAJ                2
+
+#define HDA_REG_OUTPAY              3 /* 0x04-0x05 */
+#define HDA_RMX_OUTPAY              3
+
+#define HDA_REG_INPAY               4 /* 0x06-0x07 */
+#define HDA_RMX_INPAY               4
+
+#define HDA_REG_GCTL                5 /* 0x08-0x0B */
+#define HDA_RMX_GCTL                5
+#define HDA_GCTL_UNSOL              RT_BIT(8)   /* Accept Unsolicited Response Enable */
+#define HDA_GCTL_FCNTRL             RT_BIT(1)   /* Flush Control */
+#define HDA_GCTL_CRST               RT_BIT(0)   /* Controller Reset */
+
+#define HDA_REG_WAKEEN              6 /* 0x0C */
+#define HDA_RMX_WAKEEN              6
+
+#define HDA_REG_STATESTS            7 /* 0x0E */
+#define HDA_RMX_STATESTS            7
+#define HDA_STATESTS_SCSF_MASK      0x7 /* State Change Status Flags (6.2.8). */
+
+#define HDA_REG_GSTS                8 /* 0x10-0x11*/
+#define HDA_RMX_GSTS                8
+#define HDA_GSTS_FSTS               RT_BIT(1)   /* Flush Status */
+
+#define HDA_REG_OUTSTRMPAY          9  /* 0x18 */
+#define HDA_RMX_OUTSTRMPAY          112
+
+#define HDA_REG_INSTRMPAY           10 /* 0x1a */
+#define HDA_RMX_INSTRMPAY           113
+
+#define HDA_REG_INTCTL              11 /* 0x20 */
+#define HDA_RMX_INTCTL              9
+#define HDA_INTCTL_GIE              RT_BIT(31)  /* Global Interrupt Enable */
+#define HDA_INTCTL_CIE              RT_BIT(30)  /* Controller Interrupt Enable */
+/* Bits 0-29 correspond to streams 0-29. */
+#define HDA_STRMINT_MASK            0xFF        /* Streams 0-7 implemented. Applies to INTCTL and INTSTS. */
+
+#define HDA_REG_INTSTS              12 /* 0x24 */
+#define HDA_RMX_INTSTS              10
+#define HDA_INTSTS_GIS              RT_BIT(31)  /* Global Interrupt Status */
+#define HDA_INTSTS_CIS              RT_BIT(30)  /* Controller Interrupt Status */
+/* Bits 0-29 correspond to streams 0-29. */
+
+#define HDA_REG_WALCLK              13 /* 0x30 */
+/* NB: HDA_RMX_WALCLK is not defined because the register is not stored in memory. */
+
+/* Note: The HDA specification defines a SSYNC register at offset 0x38. The
+ * ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches
+ * the datasheet.
+ */
+#define HDA_REG_SSYNC               14 /* 0x34 */
+#define HDA_RMX_SSYNC               12
+
+#define HDA_REG_CORBLBASE           15 /* 0x40 */
+#define HDA_RMX_CORBLBASE           13
+
+#define HDA_REG_CORBUBASE           16 /* 0x44 */
+#define HDA_RMX_CORBUBASE           14
+
+#define HDA_REG_CORBWP              17 /* 0x48 */
+#define HDA_RMX_CORBWP              15
+
+#define HDA_REG_CORBRP              18 /* 0x4A */
+#define HDA_RMX_CORBRP              16
+#define HDA_CORBRP_RST              RT_BIT(15)  /* CORB Read Pointer Reset */
+
+#define HDA_REG_CORBCTL             19 /* 0x4C */
+#define HDA_RMX_CORBCTL             17
+#define HDA_CORBCTL_DMA             RT_BIT(1)   /* Enable CORB DMA Engine */
+#define HDA_CORBCTL_CMEIE           RT_BIT(0)   /* CORB Memory Error Interrupt Enable */
+
+#define HDA_REG_CORBSTS             20 /* 0x4D */
+#define HDA_RMX_CORBSTS             18
+
+#define HDA_REG_CORBSIZE            21 /* 0x4E */
+#define HDA_RMX_CORBSIZE            19
+/* NB: Up to and including ICH 10, sizes of CORB and RIRB are fixed at 256 entries. */
+
+#define HDA_REG_RIRBLBASE           22 /* 0x50 */
+#define HDA_RMX_RIRBLBASE           20
+
+#define HDA_REG_RIRBUBASE           23 /* 0x54 */
+#define HDA_RMX_RIRBUBASE           21
+
+#define HDA_REG_RIRBWP              24 /* 0x58 */
+#define HDA_RMX_RIRBWP              22
+#define HDA_RIRBWP_RST              RT_BIT(15)  /* RIRB Write Pointer Reset */
+
+#define HDA_REG_RINTCNT             25 /* 0x5A */
+#define HDA_RMX_RINTCNT             23
+#define RINTCNT_N(pThis)            (HDA_REG(pThis, RINTCNT) & 0xff)
+
+#define HDA_REG_RIRBCTL             26 /* 0x5C */
+#define HDA_RMX_RIRBCTL             24
+#define HDA_RIRBCTL_ROIC            RT_BIT(2)   /* Response Overrun Interrupt Control */
+#define HDA_RIRBCTL_RDMAEN          RT_BIT(1)   /* RIRB DMA Enable */
+#define HDA_RIRBCTL_RINTCTL         RT_BIT(0)   /* Response Interrupt Control */
+
+#define HDA_REG_RIRBSTS             27 /* 0x5D */
+#define HDA_RMX_RIRBSTS             25
+#define HDA_RIRBSTS_RIRBOIS         RT_BIT(2)   /* Response Overrun Interrupt Status */
+#define HDA_RIRBSTS_RINTFL          RT_BIT(0)   /* Response Interrupt Flag */
+
+#define HDA_REG_RIRBSIZE            28 /* 0x5E */
+#define HDA_RMX_RIRBSIZE            26
+
+#define HDA_REG_IC                  29 /* 0x60 */
+#define HDA_RMX_IC                  27
+
+#define HDA_REG_IR                  30 /* 0x64 */
+#define HDA_RMX_IR                  28
+
+#define HDA_REG_IRS                 31 /* 0x68 */
+#define HDA_RMX_IRS                 29
+#define HDA_IRS_IRV                 RT_BIT(1)   /* Immediate Result Valid */
+#define HDA_IRS_ICB                 RT_BIT(0)   /* Immediate Command Busy */
+
+#define HDA_REG_DPLBASE             32 /* 0x70 */
+#define HDA_RMX_DPLBASE             30
+
+#define HDA_REG_DPUBASE             33 /* 0x74 */
+#define HDA_RMX_DPUBASE             31
+
+#define DPBASE_ADDR_MASK            (~(uint64_t)0x7f)
+
+#define HDA_STREAM_REG_DEF(name, num)           (HDA_REG_SD##num##name)
+#define HDA_STREAM_RMX_DEF(name, num)           (HDA_RMX_SD##num##name)
+/* Note: sdnum here _MUST_ be stream reg number [0,7]. */
+#define HDA_STREAM_REG(pThis, name, sdnum)      (HDA_REG_IND((pThis), HDA_REG_SD0##name + (sdnum) * 10))
+
+#define HDA_SD_NUM_FROM_REG(pThis, func, reg)   ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
+
+/** @todo Condense marcos! */
+
+#define HDA_REG_SD0CTL              HDA_NUM_GENERAL_REGS /* 0x80; other streams offset by 0x20 */
+#define HDA_RMX_SD0CTL              32
+#define HDA_RMX_SD1CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
+#define HDA_RMX_SD2CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 20)
+#define HDA_RMX_SD3CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 30)
+#define HDA_RMX_SD4CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 40)
+#define HDA_RMX_SD5CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 50)
+#define HDA_RMX_SD6CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 60)
+#define HDA_RMX_SD7CTL              (HDA_STREAM_RMX_DEF(CTL, 0) + 70)
+
+#define HDA_SDCTL_NUM_MASK          0xF
+#define HDA_SDCTL_NUM_SHIFT         20
+#define HDA_SDCTL_DIR               RT_BIT(19)  /* Direction (Bidirectional streams only!) */
+#define HDA_SDCTL_TP                RT_BIT(18)  /* Traffic Priority (PCI Express) */
+#define HDA_SDCTL_STRIPE_MASK       0x3
+#define HDA_SDCTL_STRIPE_SHIFT      16
+#define HDA_SDCTL_DEIE              RT_BIT(4)   /* Descriptor Error Interrupt Enable */
+#define HDA_SDCTL_FEIE              RT_BIT(3)   /* FIFO Error Interrupt Enable */
+#define HDA_SDCTL_IOCE              RT_BIT(2)   /* Interrupt On Completion Enable */
+#define HDA_SDCTL_RUN               RT_BIT(1)   /* Stream Run */
+#define HDA_SDCTL_SRST              RT_BIT(0)   /* Stream Reset */
+
+#define HDA_REG_SD0STS              35 /* 0x83; other streams offset by 0x20 */
+#define HDA_RMX_SD0STS              33
+#define HDA_RMX_SD1STS              (HDA_STREAM_RMX_DEF(STS, 0) + 10)
+#define HDA_RMX_SD2STS              (HDA_STREAM_RMX_DEF(STS, 0) + 20)
+#define HDA_RMX_SD3STS              (HDA_STREAM_RMX_DEF(STS, 0) + 30)
+#define HDA_RMX_SD4STS              (HDA_STREAM_RMX_DEF(STS, 0) + 40)
+#define HDA_RMX_SD5STS              (HDA_STREAM_RMX_DEF(STS, 0) + 50)
+#define HDA_RMX_SD6STS              (HDA_STREAM_RMX_DEF(STS, 0) + 60)
+#define HDA_RMX_SD7STS              (HDA_STREAM_RMX_DEF(STS, 0) + 70)
+
+#define HDA_SDSTS_FIFORDY           RT_BIT(5)   /* FIFO Ready */
+#define HDA_SDSTS_DESE              RT_BIT(4)   /* Descriptor Error */
+#define HDA_SDSTS_FIFOE             RT_BIT(3)   /* FIFO Error */
+#define HDA_SDSTS_BCIS              RT_BIT(2)   /* Buffer Completion Interrupt Status */
+
+#define HDA_REG_SD0LPIB             36 /* 0x84; other streams offset by 0x20 */
+#define HDA_REG_SD1LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 10) /* 0xA4 */
+#define HDA_REG_SD2LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 20) /* 0xC4 */
+#define HDA_REG_SD3LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 30) /* 0xE4 */
+#define HDA_REG_SD4LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 40) /* 0x104 */
+#define HDA_REG_SD5LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 50) /* 0x124 */
+#define HDA_REG_SD6LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 60) /* 0x144 */
+#define HDA_REG_SD7LPIB             (HDA_STREAM_REG_DEF(LPIB, 0) + 70) /* 0x164 */
+#define HDA_RMX_SD0LPIB             34
+#define HDA_RMX_SD1LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 10)
+#define HDA_RMX_SD2LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 20)
+#define HDA_RMX_SD3LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 30)
+#define HDA_RMX_SD4LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 40)
+#define HDA_RMX_SD5LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 50)
+#define HDA_RMX_SD6LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 60)
+#define HDA_RMX_SD7LPIB             (HDA_STREAM_RMX_DEF(LPIB, 0) + 70)
+
+#define HDA_REG_SD0CBL              37 /* 0x88; other streams offset by 0x20 */
+#define HDA_RMX_SD0CBL              35
+#define HDA_RMX_SD1CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 10)
+#define HDA_RMX_SD2CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 20)
+#define HDA_RMX_SD3CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 30)
+#define HDA_RMX_SD4CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 40)
+#define HDA_RMX_SD5CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 50)
+#define HDA_RMX_SD6CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 60)
+#define HDA_RMX_SD7CBL              (HDA_STREAM_RMX_DEF(CBL, 0) + 70)
+
+#define HDA_REG_SD0LVI              38 /* 0x8C; other streams offset by 0x20 */
+#define HDA_RMX_SD0LVI              36
+#define HDA_RMX_SD1LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 10)
+#define HDA_RMX_SD2LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 20)
+#define HDA_RMX_SD3LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 30)
+#define HDA_RMX_SD4LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 40)
+#define HDA_RMX_SD5LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 50)
+#define HDA_RMX_SD6LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 60)
+#define HDA_RMX_SD7LVI              (HDA_STREAM_RMX_DEF(LVI, 0) + 70)
+
+#define HDA_REG_SD0FIFOW            39 /* 0x8E; other streams offset by 0x20 */
+#define HDA_RMX_SD0FIFOW            37
+#define HDA_RMX_SD1FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 10)
+#define HDA_RMX_SD2FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 20)
+#define HDA_RMX_SD3FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 30)
+#define HDA_RMX_SD4FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 40)
+#define HDA_RMX_SD5FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 50)
+#define HDA_RMX_SD6FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 60)
+#define HDA_RMX_SD7FIFOW            (HDA_STREAM_RMX_DEF(FIFOW, 0) + 70)
+
+/*
+ * ICH6 datasheet defined limits for FIFOW values (18.2.38).
+ */
+#define HDA_SDFIFOW_8B              0x2
+#define HDA_SDFIFOW_16B             0x3
+#define HDA_SDFIFOW_32B             0x4
+
+#define HDA_REG_SD0FIFOS            40 /* 0x90; other streams offset by 0x20 */
+#define HDA_RMX_SD0FIFOS            38
+#define HDA_RMX_SD1FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 10)
+#define HDA_RMX_SD2FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 20)
+#define HDA_RMX_SD3FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 30)
+#define HDA_RMX_SD4FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 40)
+#define HDA_RMX_SD5FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 50)
+#define HDA_RMX_SD6FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 60)
+#define HDA_RMX_SD7FIFOS            (HDA_STREAM_RMX_DEF(FIFOS, 0) + 70)
+
+#define HDA_SDIFIFO_120B            0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
+#define HDA_SDIFIFO_160B            0x9F /* 20-, 24-bit Input Streams Streams */
+
+#define HDA_SDOFIFO_16B             0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_32B             0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_64B             0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_128B            0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_192B            0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_256B            0xFF /* 20-, 24-bit Output Streams */
+
+#define HDA_REG_SD0FMT              41 /* 0x92; other streams offset by 0x20 */
+#define HDA_RMX_SD0FMT              39
+#define HDA_RMX_SD1FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 10)
+#define HDA_RMX_SD2FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 20)
+#define HDA_RMX_SD3FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 30)
+#define HDA_RMX_SD4FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 40)
+#define HDA_RMX_SD5FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 50)
+#define HDA_RMX_SD6FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 60)
+#define HDA_RMX_SD7FMT              (HDA_STREAM_RMX_DEF(FMT, 0) + 70)
+
+#define HDA_REG_SD0BDPL             42 /* 0x98; other streams offset by 0x20 */
+#define HDA_RMX_SD0BDPL             40
+#define HDA_RMX_SD1BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 10)
+#define HDA_RMX_SD2BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 20)
+#define HDA_RMX_SD3BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 30)
+#define HDA_RMX_SD4BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 40)
+#define HDA_RMX_SD5BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 50)
+#define HDA_RMX_SD6BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 60)
+#define HDA_RMX_SD7BDPL             (HDA_STREAM_RMX_DEF(BDPL, 0) + 70)
+
+#define HDA_REG_SD0BDPU             43 /* 0x9C; other streams offset by 0x20 */
+#define HDA_RMX_SD0BDPU             41
+#define HDA_RMX_SD1BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 10)
+#define HDA_RMX_SD2BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 20)
+#define HDA_RMX_SD3BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 30)
+#define HDA_RMX_SD4BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 40)
+#define HDA_RMX_SD5BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 50)
+#define HDA_RMX_SD6BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 60)
+#define HDA_RMX_SD7BDPU             (HDA_STREAM_RMX_DEF(BDPU, 0) + 70)
+
+#define HDA_CODEC_CAD_SHIFT         28
+/* Encodes the (required) LUN into a codec command. */
+#define HDA_CODEC_CMD(cmd, lun)     ((cmd) | (lun << HDA_CODEC_CAD_SHIFT))
 
 #define HDA_SDFMT_NON_PCM_SHIFT                            15
@@ -72,4 +484,119 @@
      | ( (_aChan)     & HDA_SDFMT_CHANNELS_MASK))
 
-#endif /* DEV_HDA_COMMON_H */
-
+/** Interrupt on completion (IOC) flag. */
+#define HDA_BDLE_FLAG_IOC           RT_BIT(0)
+
+/*********************************************************************************************************************************
+*   Prototypes                                                                                                                 *
+*********************************************************************************************************************************/
+
+/** The HDA controller. */
+typedef struct HDASTATE *PHDASTATE;
+/** The HDA stream. */
+typedef struct HDASTREAM *PHDASTREAM;
+
+typedef struct HDAMIXERSINK *PHDAMIXERSINK;
+
+
+/**
+ * Internal state of a Buffer Descriptor List Entry (BDLE),
+ * needed to keep track of the data needed for the actual device
+ * emulation.
+ */
+typedef struct HDABDLESTATE
+{
+    /** Own index within the BDL (Buffer Descriptor List). */
+    uint32_t     u32BDLIndex;
+    /** Number of bytes below the stream's FIFO watermark (SDFIFOW).
+     *  Used to check if we need fill up the FIFO again. */
+    uint32_t     cbBelowFIFOW;
+    /** Current offset in DMA buffer (in bytes).*/
+    uint32_t     u32BufOff;
+    uint32_t     Padding;
+} HDABDLESTATE, *PHDABDLESTATE;
+
+/**
+ * BDL description structure.
+ * Do not touch this, as this must match to the HDA specs.
+ */
+typedef struct HDABDLEDESC
+{
+    /** Starting address of the actual buffer. Must be 128-bit aligned. */
+    uint64_t     u64BufAdr;
+    /** Size of the actual buffer (in bytes). */
+    uint32_t     u32BufSize;
+    /** Bit 0: Interrupt on completion; the controller will generate
+     *  an interrupt when the last byte of the buffer has been
+     *  fetched by the DMA engine.
+     *
+     *  Rest is reserved for further use and must be 0. */
+    uint32_t     fFlags;
+} HDABDLEDESC, *PHDABDLEDESC;
+
+/**
+ * Buffer Descriptor List Entry (BDLE) (3.6.3).
+ */
+typedef struct HDABDLE
+{
+    /** The actual BDL description. */
+    HDABDLEDESC  Desc;
+    /** Internal state of this BDLE.
+     *  Not part of the actual BDLE registers. */
+    HDABDLESTATE State;
+} HDABDLE, *PHDABDLE;
+
+/** @name Object lookup functions.
+ * @{
+ */
+PDMAUDIODIR   hdaGetDirFromSD(uint8_t uSD);
+PHDASTREAM    hdaStreamGetFromSD(PHDASTATE pThis, uint8_t uSD);
+PHDASTREAM    hdaSinkGetStream(PHDASTATE pThis, PHDAMIXERSINK pSink);
+/** @} */
+
+/** @name Interrupt functions.
+ * @{
+ */
+#ifdef DEBUG
+int           hdaProcessInterrupt(PHDASTATE pThis, const char *pszSource);
+#else
+int           hdaProcessInterrupt(PHDASTATE pThis);
+#endif
+/** @} */
+
+/** @name Wall clock (WALCLK) functions.
+ * @{
+ */
+uint64_t      hdaWalClkGetCurrent(PHDASTATE pThis);
+#ifdef IN_RING3
+bool          hdaWalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce);
+#endif
+/** @} */
+
+/** @name DMA utility functions.
+ * @{
+ */
+int           hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead);
+int           hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten);
+/** @} */
+
+/** @name Register functions.
+ * @{
+ */
+uint32_t      hdaGetINTSTS(PHDASTATE pThis);
+#ifdef IN_RING3
+int           hdaSDFMTToPCMProps(uint32_t u32SDFMT, PPDMAUDIOPCMPROPS pProps);
+#endif /* IN_RING3 */
+/** @} */
+
+/** @name BDLE (Buffer Descriptor List Entry) functions.
+ * @{
+ */
+#ifdef IN_RING3
+int           hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
+bool          hdaBDLEIsComplete(PHDABDLE pBDLE);
+bool          hdaBDLENeedsInterrupt(PHDABDLE pBDLE);
+#endif /* IN_RING3 */
+/** @} */
+
+#endif /* DEV_HDA_H_COMMON */
+
Index: /trunk/src/VBox/Devices/Audio/HDACodec.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDACodec.h	(revision 67898)
+++ /trunk/src/VBox/Devices/Audio/HDACodec.h	(revision 67899)
@@ -18,4 +18,8 @@
 #ifndef DEV_HDA_CODEC_H
 #define DEV_HDA_CODEC_H
+
+#include <iprt/list.h>
+
+#include "AudioMixer.h"
 
 /** The ICH HDA (Intel) controller. */
Index: /trunk/src/VBox/Devices/Audio/HDAStream.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 67899)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 67899)
@@ -0,0 +1,1357 @@
+/* $Id$ */
+/** @file
+ * HDAStream.cpp - Stream functions for HD Audio.
+ */
+
+/*
+ * Copyright (C) 2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEV_HDA
+#include <VBox/log.h>
+
+#include <iprt/mem.h>
+#include <iprt/semaphore.h>
+
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdmaudioifs.h>
+
+#include "DrvAudio.h"
+
+#include "DevHDA.h"
+#include "HDAStream.h"
+
+
+#ifdef IN_RING3
+
+/**
+ * Creates an HDA stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to create.
+ * @param   pThis               HDA state to assign the HDA stream to.
+ */
+int hdaStreamCreate(PHDASTREAM pStream, PHDASTATE pThis)
+{
+    RT_NOREF(pThis);
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+
+    pStream->u8SD           = UINT8_MAX;
+    pStream->pMixSink       = NULL;
+    pStream->pHDAState      = pThis;
+
+    pStream->State.fInReset = false;
+#ifdef HDA_USE_DMA_ACCESS_HANDLER
+    RTListInit(&pStream->State.lstDMAHandlers);
+#endif
+
+    int rc = RTCircBufCreate(&pStream->State.pCircBuf, _64K); /** @todo Make this configurable. */
+    if (RT_SUCCESS(rc))
+    {
+        rc = hdaStreamPeriodCreate(&pStream->State.Period);
+        if (RT_SUCCESS(rc))
+            rc = RTCritSectInit(&pStream->State.CritSect);
+    }
+
+#ifdef DEBUG
+    int rc2 = RTCritSectInit(&pStream->Dbg.CritSect);
+    AssertRC(rc2);
+#endif
+
+    return rc;
+}
+
+/**
+ * Destroys an HDA stream.
+ *
+ * @param   pStream             HDA stream to destroy.
+ */
+void hdaStreamDestroy(PHDASTREAM pStream)
+{
+    AssertPtrReturnVoid(pStream);
+
+    LogFlowFunc(("[SD%RU8]: Destroying ...\n", pStream->u8SD));
+
+    hdaStreamMapDestroy(&pStream->State.Mapping);
+
+    int rc2;
+
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+    rc2 = hdaStreamAsyncIODestroy(pStream);
+    AssertRC(rc2);
+#else
+    RT_NOREF(pThis);
+#endif
+
+    rc2 = RTCritSectDelete(&pStream->State.CritSect);
+    AssertRC(rc2);
+
+    if (pStream->State.pCircBuf)
+    {
+        RTCircBufDestroy(pStream->State.pCircBuf);
+        pStream->State.pCircBuf = NULL;
+    }
+
+    hdaStreamPeriodDestroy(&pStream->State.Period);
+
+#ifdef DEBUG
+    rc2 = RTCritSectDelete(&pStream->Dbg.CritSect);
+    AssertRC(rc2);
+#endif
+
+    LogFlowFuncLeave();
+}
+
+/**
+ * Initializes an HDA stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to initialize.
+ * @param   uSD                 SD (stream descriptor) number to assign the HDA stream to.
+ */
+int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
+{
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+
+    PHDASTATE pThis = pStream->pHDAState;
+    AssertPtr(pThis);
+
+    pStream->u8SD       = uSD;
+    pStream->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStream->u8SD),
+                                      HDA_STREAM_REG(pThis, BDPU, pStream->u8SD));
+    pStream->u16LVI     = HDA_STREAM_REG(pThis, LVI, pStream->u8SD);
+    pStream->u32CBL     = HDA_STREAM_REG(pThis, CBL, pStream->u8SD);
+    pStream->u16FIFOS   = HDA_STREAM_REG(pThis, FIFOS, pStream->u8SD) + 1;
+
+    /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
+    hdaStreamUpdateLPIB(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
+
+    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg;
+
+    int rc = hdaSDFMTToPCMProps(HDA_STREAM_REG(pThis, FMT, uSD), &pCfg->Props);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("HDA: Warning: Format 0x%x for stream #%RU8 not supported\n", HDA_STREAM_REG(pThis, FMT, uSD), uSD));
+        return rc;
+    }
+
+    /* Set the stream's direction. */
+    pCfg->enmDir = hdaGetDirFromSD(pStream->u8SD);
+
+    /* The the stream's name, based on the direction. */
+    switch (pCfg->enmDir)
+    {
+        case PDMAUDIODIR_IN:
+# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
+#  error "Implement me!"
+# else
+            pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;
+            pCfg->enmLayout         = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
+            RTStrCopy(pCfg->szName, sizeof(pCfg->szName), "Line In");
+# endif
+            break;
+
+        case PDMAUDIODIR_OUT:
+            /* Destination(s) will be set in hdaAddStreamOut(),
+             * based on the channels / stream layout. */
+            break;
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    /*
+     * Initialize the stream mapping in any case, regardless if
+     * we support surround audio or not. This is needed to handle
+     * the supported channels within a single audio stream, e.g. mono/stereo.
+     *
+     * In other words, the stream mapping *always* knows the real
+     * number of channels in a single audio stream.
+     */
+    rc = hdaStreamMapInit(&pStream->State.Mapping, &pCfg->Props);
+    AssertRCReturn(rc, rc);
+
+    LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16, rc=%Rrc\n",
+             pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS, rc));
+
+    return rc;
+}
+
+/**
+ * Resets an HDA stream.
+ *
+ * @param   pThis               HDA state.
+ * @param   pStream             HDA stream to reset.
+ * @param   uSD                 Stream descriptor (SD) number to use for this stream.
+ */
+void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD)
+{
+    AssertPtrReturnVoid(pThis);
+    AssertPtrReturnVoid(pStream);
+    AssertReturnVoid(uSD < HDA_MAX_STREAMS);
+
+# ifdef VBOX_STRICT
+    AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_RUN),
+                     ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
+# endif
+
+    LogFunc(("[SD%RU8]: Reset\n", uSD));
+
+    /*
+     * Set reset state.
+     */
+    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false); /* No nested calls. */
+    ASMAtomicXchgBool(&pStream->State.fInReset, true);
+
+    /*
+     * Second, initialize the registers.
+     */
+    HDA_STREAM_REG(pThis, STS,   uSD) = HDA_SDSTS_FIFORDY;
+    /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
+     * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
+    HDA_STREAM_REG(pThis, CTL,   uSD) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_SRST);
+    /* ICH6 defines default values (120 bytes for input and 192 bytes for output descriptors) of FIFO size. 18.2.39. */
+    HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDIFIFO_120B : HDA_SDOFIFO_192B;
+    /* See 18.2.38: Always defaults to 0x4 (32 bytes). */
+    HDA_STREAM_REG(pThis, FIFOW, uSD) = HDA_SDFIFOW_32B;
+    HDA_STREAM_REG(pThis, LPIB,  uSD) = 0;
+    HDA_STREAM_REG(pThis, CBL,   uSD) = 0;
+    HDA_STREAM_REG(pThis, LVI,   uSD) = 0;
+    HDA_STREAM_REG(pThis, FMT,   uSD) = 0;
+    HDA_STREAM_REG(pThis, BDPU,  uSD) = 0;
+    HDA_STREAM_REG(pThis, BDPL,  uSD) = 0;
+
+#ifdef HDA_USE_DMA_ACCESS_HANDLER
+    hdaStreamUnregisterDMAHandlers(pThis, pStream);
+#endif
+
+    RT_ZERO(pStream->State.BDLE);
+    pStream->State.uCurBDLE = 0;
+
+    if (pStream->State.pCircBuf)
+        RTCircBufReset(pStream->State.pCircBuf);
+
+    /* Reset stream map. */
+    hdaStreamMapReset(&pStream->State.Mapping);
+
+    /* (Re-)initialize the stream with current values. */
+    int rc2 = hdaStreamInit(pStream, uSD);
+    AssertRC(rc2);
+
+    /* Reset the stream's period. */
+    hdaStreamPeriodReset(&pStream->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;
+#endif
+
+    /* Report that we're done resetting this stream. */
+    HDA_STREAM_REG(pThis, CTL,   uSD) = 0;
+
+    LogFunc(("[SD%RU8] Reset\n", uSD));
+
+    /* Exit reset mode. */
+    ASMAtomicXchgBool(&pStream->State.fInReset, false);
+}
+
+/**
+ * Enables or disables an HDA audio stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to enable or disable.
+ * @param   fEnable             Whether to enable or disble the stream.
+ */
+int hdaStreamEnable(PHDASTREAM pStream, bool fEnable)
+{
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+
+    LogFunc(("[SD%RU8]: fEnable=%RTbool, pMixSink=%p\n", pStream->u8SD, fEnable, pStream->pMixSink));
+
+    int rc = VINF_SUCCESS;
+
+    if (pStream->pMixSink) /* Stream attached to a sink? */
+    {
+        AUDMIXSINKCMD enmCmd = fEnable
+                             ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
+
+        /* First, enable or disable the stream and the stream's sink, if any. */
+        if (pStream->pMixSink->pMixSink)
+            rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
+    }
+
+    LogFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8SD, rc));
+    return rc;
+}
+
+/**
+ * Returns the number of outstanding stream data bytes which need to be processed
+ * by the DMA engine assigned to this stream.
+ *
+ * @return Number of bytes for the DMA engine to process.
+ */
+uint32_t hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStream)
+{
+    AssertPtrReturn(pThis, 0);
+    AssertPtrReturn(pStream, 0);
+
+    if (!RT_BOOL(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN))
+    {
+        AssertFailed(); /* Should never happen. */
+        return 0;
+    }
+
+    /* Determine how much for the current BDL entry we have left to transfer. */
+    PHDABDLE pBDLE  = &pStream->State.BDLE;
+    const uint32_t cbBDLE = RT_MIN(pBDLE->Desc.u32BufSize, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
+
+    /* Determine how much we (still) can stuff in the stream's internal FIFO.  */
+    const uint32_t cbCircBuf   = (uint32_t)RTCircBufFree(pStream->State.pCircBuf);
+
+    uint32_t cbToTransfer = cbBDLE;
+
+    /* Make sure that we don't transfer more than our FIFO can hold at the moment.
+     * As the host sets the overall pace it needs to process some of the FIFO data first before
+     * we can issue a new DMA data transfer. */
+    if (cbToTransfer > cbCircBuf)
+        cbToTransfer = cbCircBuf;
+
+    Log3Func(("[SD%RU8] LPIB=%RU32 CBL=%RU32 cbCircBuf=%RU32, -> cbToTransfer=%RU32 %R[bdle]\n", pStream->u8SD,
+              HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u32CBL, cbCircBuf, cbToTransfer, pBDLE));
+    return cbToTransfer;
+}
+
+/**
+ * Increases the amount of transferred (audio) data of an HDA stream and
+ * reports this as needed to the guest.
+ *
+ * @param  pStream              HDA stream to increase amount for.
+ * @param  cbInc                Amount (in bytes) to increase.
+ */
+void hdaStreamTransferInc(PHDASTREAM pStream, uint32_t cbInc)
+{
+    AssertPtrReturnVoid(pStream);
+
+    if (!cbInc)
+        return;
+
+    const PHDASTATE pThis  = pStream->pHDAState;
+
+    const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
+
+    Log3Func(("[SD%RU8] %RU32 + %RU32 -> %RU32, CBL=%RU32\n",
+              pStream->u8SD, u32LPIB, cbInc, u32LPIB + cbInc, pStream->u32CBL));
+
+    hdaStreamUpdateLPIB(pStream, u32LPIB + cbInc);
+}
+
+/**
+ * Retrieves the available size of (buffered) audio data (in bytes) of a given HDA stream.
+ *
+ * @returns Available data (in bytes).
+ * @param   pStream             HDA stream to retrieve size for.
+ */
+uint32_t hdaStreamGetUsed(PHDASTREAM pStream)
+{
+    AssertPtrReturn(pStream, 0);
+
+    if (!pStream->State.pCircBuf)
+        return 0;
+
+    return (uint32_t)RTCircBufUsed(pStream->State.pCircBuf);
+}
+
+/**
+ * Retrieves the free size of audio data (in bytes) of a given HDA stream.
+ *
+ * @returns Free data (in bytes).
+ * @param   pStream             HDA stream to retrieve size for.
+ */
+uint32_t hdaStreamGetFree(PHDASTREAM pStream)
+{
+    AssertPtrReturn(pStream, 0);
+
+    if (!pStream->State.pCircBuf)
+        return 0;
+
+    return (uint32_t)RTCircBufFree(pStream->State.pCircBuf);
+}
+
+
+/**
+ * Writes audio data from a mixer sink into an HDA stream's DMA buffer.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to write to.
+ * @param   cbToWrite           Number of bytes to write.
+ * @param   pcbWritten          Number of bytes written. Optional.
+ */
+int hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
+{
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
+    /* pcbWritten is optional. */
+
+    PHDAMIXERSINK pSink = pStream->pMixSink;
+    if (!pSink)
+    {
+        AssertMsgFailed(("[SD%RU8]: Can't write to a stream with no sink attached\n", pStream->u8SD));
+
+        if (pcbWritten)
+            *pcbWritten = 0;
+        return VINF_SUCCESS;
+    }
+
+    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
+    AssertPtr(pCircBuf);
+
+    int rc = VINF_SUCCESS;
+
+    uint32_t cbWrittenTotal = 0;
+    uint32_t cbLeft         = RT_MIN(cbToWrite, (uint32_t)RTCircBufFree(pCircBuf));
+
+    while (cbLeft)
+    {
+        void *pvDst;
+        size_t cbDst;
+
+        uint32_t cbRead = 0;
+
+        RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst);
+
+        if (cbDst)
+        {
+            rc = AudioMixerSinkRead(pSink->pMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead);
+            AssertRC(rc);
+
+            Assert(cbDst >= cbRead);
+            Log2Func(("[SD%RU8]: %zu/%zu bytes read\n", pStream->u8SD, cbRead, cbDst));
+
+#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
+            RTFILE fh;
+            RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaStreamWrite.pcm",
+                       RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+            RTFileWrite(fh, pvDst, cbRead, NULL);
+            RTFileClose(fh);
+#endif
+        }
+
+        RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
+
+        if (RT_FAILURE(rc))
+            break;
+
+        Assert(cbLeft  >= cbRead);
+        cbLeft         -= cbRead;
+
+        cbWrittenTotal += cbRead;
+    }
+
+    if (pcbWritten)
+        *pcbWritten = cbWrittenTotal;
+
+    return rc;
+}
+
+
+/**
+ * Reads audio data from an HDA stream's DMA buffer and writes into a specified mixer sink.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to read audio data from.
+ * @param   cbToRead            Number of bytes to read.
+ * @param   pcbRead             Number of bytes read. Optional.
+ */
+int hdaStreamRead(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;
+    AssertPtr(pCircBuf);
+
+    int rc = VINF_SUCCESS;
+
+    uint32_t cbReadTotal = 0;
+    uint32_t cbLeft      = RT_MIN(cbToRead, (uint32_t)RTCircBufUsed(pCircBuf));
+
+    while (cbLeft)
+    {
+        void *pvSrc;
+        size_t cbSrc;
+
+        uint32_t cbWritten = 0;
+
+        RTCircBufAcquireReadBlock(pCircBuf, cbLeft, &pvSrc, &cbSrc);
+
+        if (cbSrc)
+        {
+#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
+            RTFILE fh;
+            RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaStreamRead.pcm",
+                       RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+            RTFileWrite(fh, pvSrc, cbSrc, NULL);
+            RTFileClose(fh);
+#endif
+            rc = AudioMixerSinkWrite(pSink->pMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten);
+            AssertRC(rc);
+
+            Assert(cbSrc >= cbWritten);
+            Log2Func(("[SD%RU8]: %zu/%zu bytes read\n", pStream->u8SD, cbWritten, cbSrc));
+        }
+
+        RTCircBufReleaseReadBlock(pCircBuf, cbWritten);
+
+        if (RT_FAILURE(rc))
+            break;
+
+        Assert(cbLeft  >= cbWritten);
+        cbLeft         -= cbWritten;
+
+        cbReadTotal    += cbWritten;
+    }
+
+    if (pcbRead)
+        *pcbRead = cbReadTotal;
+
+    return rc;
+}
+
+uint32_t hdaStreamTransferGetElapsed(PHDASTREAM pStream)
+{
+    AssertPtr(pStream->pHDAState->pTimer);
+    const uint64_t cTicksNow     = TMTimerGet(pStream->pHDAState->pTimer);
+    const uint64_t cTicksPerSec  = TMTimerGetFreq(pStream->pHDAState->pTimer);
+
+    const uint64_t cTicksElapsed = cTicksNow - pStream->State.uTimerTS;
+#ifdef DEBUG
+    const uint64_t cMsElapsed    = cTicksElapsed / (cTicksPerSec / 1000);
+#endif
+
+    AssertPtr(pStream->pHDAState->pCodec);
+
+    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg;
+
+    /* A stream *always* runs with 48 kHz device-wise, regardless of the actual stream input/output format (Hz) being set. */
+    uint32_t csPerPeriod = (int)((pCfg->Props.cChannels * cTicksElapsed * 48000 /* Hz */ + cTicksPerSec) / cTicksPerSec / 2);
+    uint32_t cbPerPeriod = csPerPeriod << pCfg->Props.cShift;
+
+    Log3Func(("[SD%RU8] %RU64ms (%zu samples, %zu bytes) elapsed\n", pStream->u8SD, cMsElapsed, csPerPeriod, cbPerPeriod));
+
+    return cbPerPeriod;
+}
+
+/**
+ * Transfers data of an HDA stream according to its usage (input / output).
+ *
+ * For an SDO (output) stream this means reading DMA data from the device to
+ * the HDA stream's internal FIFO buffer.
+ *
+ * For an SDI (input) stream this is reading audio data from the HDA stream's
+ * internal FIFO buffer and writing it as DMA data to the device.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to update.
+ * @param   cbToProcessMax      Maximum of data (in bytes) to process.
+ */
+int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
+{
+    AssertPtrReturn(pStream,        VERR_INVALID_POINTER);
+    AssertReturn(cbToProcessMax,    VERR_INVALID_PARAMETER);
+
+    hdaStreamLock(pStream);
+
+    PHDASTATE pThis = pStream->pHDAState;
+    AssertPtr(pThis);
+
+    PHDASTREAMPERIOD pPeriod = &pStream->State.Period;
+    int rc = hdaStreamPeriodLock(pPeriod);
+    AssertRC(rc);
+
+    bool fProceed = true;
+
+    /* Stream not running? */
+    if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN))
+    {
+        Log3Func(("[SD%RU8] RUN bit not set\n", pStream->u8SD));
+        fProceed = false;
+    }
+    /* Period complete? */
+    else if (hdaStreamPeriodIsComplete(pPeriod))
+    {
+        Log3Func(("[SD%RU8] Period is complete, nothing to do\n", pStream->u8SD));
+        fProceed = false;
+    }
+
+    if (!fProceed)
+    {
+        hdaStreamPeriodUnlock(pPeriod);
+        hdaStreamUnlock(pStream);
+        return VINF_SUCCESS;
+    }
+
+    /* Sanity checks. */
+    Assert(pStream->u8SD < HDA_MAX_STREAMS);
+    Assert(pStream->u64BDLBase);
+    Assert(pStream->u32CBL);
+
+    /* State sanity checks. */
+    Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false);
+
+    /* Fetch first / next BDL entry. */
+    PHDABDLE pBDLE = &pStream->State.BDLE;
+    if (hdaBDLEIsComplete(pBDLE))
+    {
+        rc = hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+        AssertRC(rc);
+    }
+
+    const uint32_t cbPeriodRemaining = hdaStreamPeriodGetRemainingFrames(pPeriod) * HDA_FRAME_SIZE;
+    Assert(cbPeriodRemaining); /* Paranoia. */
+
+    const uint32_t cbElapsed         = hdaStreamTransferGetElapsed(pStream);
+    Assert(cbElapsed);         /* Paranoia. */
+
+    /* Limit the data to read, as this routine could be delayed and therefore
+     * report wrong (e.g. too much) cbElapsed bytes. */
+    uint32_t cbLeft                  = RT_MIN(RT_MIN(cbPeriodRemaining, cbElapsed), cbToProcessMax);
+
+    Log3Func(("[SD%RU8] cbPeriodRemaining=%RU32, cbElapsed=%RU32, cbToProcessMax=%RU32 -> cbLeft=%RU32\n",
+              pStream->u8SD, cbPeriodRemaining, cbElapsed, cbToProcessMax, cbLeft));
+
+    Assert(cbLeft % HDA_FRAME_SIZE == 0); /* Paranoia. */
+
+    while (cbLeft)
+    {
+        uint32_t cbChunk = RT_MIN(hdaStreamGetTransferSize(pThis, pStream), cbLeft);
+        if (!cbChunk)
+            break;
+
+        uint32_t cbDMA   = 0;
+
+        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
+        {
+            STAM_PROFILE_START(&pThis->StatOut, a);
+
+            rc = hdaDMARead(pThis, pStream, cbChunk, &cbDMA /* pcbRead */);
+            if (RT_FAILURE(rc))
+                LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
+
+            STAM_PROFILE_STOP(&pThis->StatOut, a);
+        }
+        else if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) /* Input (SDI). */
+        {
+            STAM_PROFILE_START(&pThis->StatIn, a);
+
+            rc = hdaDMAWrite(pThis, pStream, cbChunk, &cbDMA /* pcbWritten */);
+            if (RT_FAILURE(rc))
+                LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
+
+            STAM_PROFILE_STOP(&pThis->StatIn, a);
+        }
+        else /** @todo Handle duplex streams? */
+            AssertFailed();
+
+        if (cbDMA)
+        {
+            Assert(cbDMA % HDA_FRAME_SIZE == 0);
+
+            /* We always increment the position of DMA buffer counter because we're always reading
+             * into an intermediate buffer. */
+            pBDLE->State.u32BufOff += (uint32_t)cbDMA;
+            Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize);
+
+            hdaStreamTransferInc(pStream, cbDMA);
+
+            uint32_t framesDMA = cbDMA / HDA_FRAME_SIZE;
+
+            /* Add the transferred frames to the period. */
+            hdaStreamPeriodInc(pPeriod, framesDMA);
+
+            /* Save the timestamp of when the last successful DMA transfer has been for this stream. */
+            pStream->State.uTimerTS = TMTimerGet(pThis->pTimer);
+
+            Assert(cbLeft >= cbDMA);
+            cbLeft        -= cbDMA;
+        }
+
+        if (hdaBDLEIsComplete(pBDLE))
+        {
+            Log3Func(("[SD%RU8] Complete: %R[bdle]\n", pStream->u8SD, pBDLE));
+
+            if (hdaBDLENeedsInterrupt(pBDLE))
+            {
+                /* 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)
+                    hdaStreamPeriodAcquireInterrupt(pPeriod);
+            }
+
+            if (pStream->State.uCurBDLE == pStream->u16LVI)
+            {
+                Assert(pStream->u32CBL == HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
+
+                pStream->State.uCurBDLE = 0;
+                hdaStreamUpdateLPIB(pStream, 0 /* LPIB */);
+            }
+            else
+                pStream->State.uCurBDLE++;
+
+            hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+
+            Log3Func(("[SD%RU8] Fetching: %R[bdle]\n", pStream->u8SD, pBDLE));
+        }
+
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    if (hdaStreamPeriodIsComplete(pPeriod))
+    {
+        Log3Func(("[SD%RU8] Period complete -- Current: %R[bdle]\n", pStream->u8SD, &pStream->State.BDLE));
+
+        /* Set the stream's BCIS bit.
+         *
+         * Note: This only must be done if the whole period is complete, and not if only
+         * one specific BDL entry is complete (if it has the IOC bit set).
+         *
+         * This will otherwise confuses the guest when it 1) deasserts the interrupt,
+         * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value.
+         *
+         * snd_hda_intel on Linux will tell. */
+        HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_SDSTS_BCIS;
+
+        /* Try updating the wall clock. */
+        const uint64_t u64WalClk  = hdaStreamPeriodGetAbsElapsedWalClk(pPeriod);
+        const bool     fWalClkSet = hdaWalClkSet(pThis, u64WalClk, false /* fForce */);
+
+        /* Does the period have any interrupts outstanding? */
+        if (hdaStreamPeriodNeedsInterrupt(pPeriod))
+        {
+            if (fWalClkSet)
+            {
+                Log3Func(("[SD%RU8] Set WALCLK to %RU64, triggering interrupt\n", pStream->u8SD, u64WalClk));
+
+                /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
+                 * ending / beginning a period. */
+#ifndef DEBUG
+                hdaProcessInterrupt(pThis);
+#else
+                hdaProcessInterrupt(pThis, __FUNCTION__);
+#endif
+            }
+        }
+        else
+        {
+            /* End the period first ... */
+            hdaStreamPeriodEnd(pPeriod);
+
+            /* ... and immediately begin the next one. */
+            hdaStreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis));
+        }
+    }
+
+    hdaStreamPeriodUnlock(pPeriod);
+
+    Log3Func(("[SD%RU8] Returning %Rrc ==========================================\n", pStream->u8SD, rc));
+
+    if (RT_FAILURE(rc))
+        LogFunc(("[SD%RU8] Failed with rc=%Rrcc\n", pStream->u8SD, rc));
+
+    hdaStreamUnlock(pStream);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Updates a HDA stream by doing its required data transfers.
+ * The host sink(s) set the overall pace.
+ *
+ * This routine is called by both, the synchronous and the asynchronous, implementations.
+ *
+ * @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 hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
+{
+    PAUDMIXSINK pSink = NULL;
+    if (   pStream->pMixSink
+        && pStream->pMixSink->pMixSink)
+    {
+        pSink = pStream->pMixSink->pMixSink;
+    }
+
+    if (!AudioMixerSinkIsActive(pSink)) /* No sink available? Bail out. */
+        return;
+
+    int rc2;
+
+    if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
+    {
+        /* Is the HDA stream ready to be written (guest output data) to? If so, by how much? */
+        const uint32_t cbFree = hdaStreamGetFree(pStream);
+
+        if (   fInTimer
+            && cbFree)
+        {
+            Log3Func(("[SD%RU8] cbFree=%RU32\n", pStream->u8SD, cbFree));
+
+            /* Do the DMA transfer. */
+            rc2 = hdaStreamTransfer(pStream, cbFree);
+            AssertRC(rc2);
+        }
+
+        /* How much (guest output) data is available at the moment for the HDA stream? */
+        uint32_t cbUsed = hdaStreamGetUsed(pStream);
+
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        if (   fInTimer
+            && cbUsed)
+        {
+            rc2 = hdaStreamAsyncIONotify(pStream);
+            AssertRC(rc2);
+        }
+        else
+        {
+#endif
+            const uint32_t cbSinkWritable = AudioMixerSinkGetWritable(pSink);
+
+            /* Do not write more than the sink can hold at the moment.
+             * The host sets the overall pace. */
+            if (cbUsed > cbSinkWritable)
+                cbUsed = cbSinkWritable;
+
+            if (cbUsed)
+            {
+                /* Read (guest output) data and write it to the stream's sink. */
+                rc2 = hdaStreamRead(pStream, cbUsed, NULL /* pcbRead */);
+                AssertRC(rc2);
+            }
+
+            /* When running synchronously, update the associated sink here.
+             * Otherwise this will be done in the device timer. */
+            rc2 = AudioMixerSinkUpdate(pSink);
+            AssertRC(rc2);
+
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        }
+#endif
+    }
+    else /* Input (SDI). */
+    {
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        if (fInTimer)
+        {
+            rc2 = hdaStreamAsyncIONotify(pStream);
+            AssertRC(rc2);
+        }
+        else
+        {
+#endif
+            rc2 = AudioMixerSinkUpdate(pSink);
+            AssertRC(rc2);
+
+            /* Is the sink ready to be read (host input data) from? If so, by how much? */
+            const uint32_t cbReadable = AudioMixerSinkGetReadable(pSink);
+
+            /* How much (guest input) data is free at the moment? */
+            uint32_t cbFree = hdaStreamGetFree(pStream);
+
+            Log3Func(("[SD%RU8] cbReadable=%RU32, cbFree=%RU32\n", pStream->u8SD, cbReadable, cbFree));
+
+            /* Do not read more than the sink can provide at the moment.
+             * The host sets the overall pace. */
+            if (cbFree > cbReadable)
+                cbFree = cbReadable;
+
+            if (cbFree)
+            {
+                /* Write (guest input) data to the stream which was read from stream's sink before. */
+                rc2 = hdaStreamWrite(pStream, cbFree, NULL /* pcbWritten */);
+                AssertRC(rc2);
+            }
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        }
+#endif
+
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        if (fInTimer)
+        {
+#endif
+            const uint32_t cbToTransfer = hdaStreamGetUsed(pStream);
+            if (cbToTransfer)
+            {
+                /* When running synchronously, do the DMA data transfers here.
+                 * Otherwise this will be done in the stream's async I/O thread. */
+                rc2 = hdaStreamTransfer(pStream, cbToTransfer);
+                AssertRC(rc2);
+            }
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+        }
+#endif
+    }
+}
+
+/**
+ * Locks an HDA stream for serialized access.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to lock.
+ */
+void hdaStreamLock(PHDASTREAM pStream)
+{
+    AssertPtrReturnVoid(pStream);
+    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
+    AssertRC(rc2);
+}
+
+/**
+ * Unlocks a formerly locked HDA stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to unlock.
+ */
+void hdaStreamUnlock(PHDASTREAM pStream)
+{
+    AssertPtrReturnVoid(pStream);
+    int rc2 = RTCritSectLeave(&pStream->State.CritSect);
+    AssertRC(rc2);
+}
+
+/**
+ * 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).
+ *
+ * @returns Set LPIB value.
+ * @param   pStream             HDA stream to update read / write position for.
+ * @param   u32LPIB             New LPIB (position) value to set.
+ */
+uint32_t hdaStreamUpdateLPIB(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);
+
+    LogFlowFunc(("[SD%RU8]: LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
+                 pStream->u8SD, u32LPIB, pThis->fDMAPosition));
+
+    /* Update LPIB in any case. */
+    HDA_STREAM_REG(pThis, LPIB, pStream->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)),
+                                        (void *)&u32LPIB, sizeof(uint32_t));
+        AssertRC(rc2);
+    }
+
+    return u32LPIB;
+}
+
+# ifdef HDA_USE_DMA_ACCESS_HANDLER
+/**
+ * Registers access handlers for a stream's BDLE DMA accesses.
+ *
+ * @returns true if registration was successful, false if not.
+ * @param   pStream             HDA stream to register BDLE access handlers for.
+ */
+bool hdaStreamRegisterDMAHandlers(PHDASTREAM pStream)
+{
+    /* At least LVI and the BDL base must be set. */
+    if (   !pStream->u16LVI
+        || !pStream->u64BDLBase)
+    {
+        return false;
+    }
+
+    hdaStreamUnregisterDMAHandlers(pStream);
+
+    LogFunc(("Registering ...\n"));
+
+    int rc = VINF_SUCCESS;
+
+    /*
+     * Create BDLE ranges.
+     */
+
+    struct BDLERANGE
+    {
+        RTGCPHYS uAddr;
+        uint32_t uSize;
+    } arrRanges[16]; /** @todo Use a define. */
+
+    size_t cRanges = 0;
+
+    for (uint16_t i = 0; i < pStream->u16LVI + 1; i++)
+    {
+        HDABDLE BDLE;
+        rc = hdaBDLEFetch(pThis, &BDLE, pStream->u64BDLBase, i /* Index */);
+        if (RT_FAILURE(rc))
+            break;
+
+        bool fAddRange = true;
+        BDLERANGE *pRange;
+
+        if (cRanges)
+        {
+            pRange = &arrRanges[cRanges - 1];
+
+            /* Is the current range a direct neighbor of the current BLDE? */
+            if ((pRange->uAddr + pRange->uSize) == BDLE.Desc.u64BufAdr)
+            {
+                /* Expand the current range by the current BDLE's size. */
+                pRange->uSize += BDLE.Desc.u32BufSize;
+
+                /* Adding a new range in this case is not needed anymore. */
+                fAddRange = false;
+
+                LogFunc(("Expanding range %zu by %RU32 (%RU32 total now)\n", cRanges - 1, BDLE.Desc.u32BufSize, pRange->uSize));
+            }
+        }
+
+        /* Do we need to add a new range? */
+        if (   fAddRange
+            && cRanges < RT_ELEMENTS(arrRanges))
+        {
+            pRange = &arrRanges[cRanges];
+
+            pRange->uAddr = BDLE.Desc.u64BufAdr;
+            pRange->uSize = BDLE.Desc.u32BufSize;
+
+            LogFunc(("Adding range %zu - 0x%x (%RU32)\n", cRanges, pRange->uAddr, pRange->uSize));
+
+            cRanges++;
+        }
+    }
+
+    LogFunc(("%zu ranges total\n", cRanges));
+
+    /*
+     * Register all ranges as DMA access handlers.
+     */
+
+    for (size_t i = 0; i < cRanges; i++)
+    {
+        BDLERANGE *pRange = &arrRanges[i];
+
+        PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)RTMemAllocZ(sizeof(HDADMAACCESSHANDLER));
+        if (!pHandler)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        RTListAppend(&pStream->State.lstDMAHandlers, &pHandler->Node);
+
+        pHandler->pStream = pStream; /* Save a back reference to the owner. */
+
+        char szDesc[32];
+        RTStrPrintf(szDesc, sizeof(szDesc), "HDA[SD%RU8 - RANGE%02zu]", pStream->u8SD, i);
+
+        int rc2 = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3), PGMPHYSHANDLERKIND_WRITE,
+                                                   hdaDMAAccessHandler,
+                                                   NULL, NULL, NULL,
+                                                   NULL, NULL, NULL,
+                                                   szDesc, &pHandler->hAccessHandlerType);
+        AssertRCBreak(rc2);
+
+        pHandler->BDLEAddr  = pRange->uAddr;
+        pHandler->BDLESize  = pRange->uSize;
+
+        /* Get first and last pages of the BDLE range. */
+        RTGCPHYS pgFirst = pRange->uAddr & ~PAGE_OFFSET_MASK;
+        RTGCPHYS pgLast  = RT_ALIGN(pgFirst + pRange->uSize, PAGE_SIZE);
+
+        /* Calculate the region size (in pages). */
+        RTGCPHYS regionSize = RT_ALIGN(pgLast - pgFirst, PAGE_SIZE);
+
+        pHandler->GCPhysFirst = pgFirst;
+        pHandler->GCPhysLast  = pHandler->GCPhysFirst + (regionSize - 1);
+
+        LogFunc(("\tRegistering region '%s': 0x%x - 0x%x (region size: %zu)\n",
+                 szDesc, pHandler->GCPhysFirst, pHandler->GCPhysLast, regionSize));
+        LogFunc(("\tBDLE @ 0x%x - 0x%x (%RU32)\n",
+                 pHandler->BDLEAddr, pHandler->BDLEAddr + pHandler->BDLESize, pHandler->BDLESize));
+
+        rc2 = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),
+                                         pHandler->GCPhysFirst, pHandler->GCPhysLast,
+                                         pHandler->hAccessHandlerType, pHandler, NIL_RTR0PTR, NIL_RTRCPTR,
+                                         szDesc);
+        AssertRCBreak(rc2);
+
+        pHandler->fRegistered = true;
+    }
+
+    LogFunc(("Registration ended with rc=%Rrc\n", rc));
+
+    return RT_SUCCESS(rc);
+}
+
+/**
+ * Unregisters access handlers of a stream's BDLEs.
+ *
+ * @param   pStream             HDA stream to unregister BDLE access handlers for.
+ */
+void hdaStreamUnregisterDMAHandlers(PHDASTREAM pStream)
+{
+    LogFunc(("\n"));
+
+    PHDADMAACCESSHANDLER pHandler, pHandlerNext;
+    RTListForEachSafe(&pStream->State.lstDMAHandlers, pHandler, pHandlerNext, HDADMAACCESSHANDLER, Node)
+    {
+        if (!pHandler->fRegistered) /* Handler not registered? Skip. */
+            continue;
+
+        LogFunc(("Unregistering 0x%x - 0x%x (%zu)\n",
+                 pHandler->GCPhysFirst, pHandler->GCPhysLast, pHandler->GCPhysLast - pHandler->GCPhysFirst));
+
+        int rc2 = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),
+                                               pHandler->GCPhysFirst);
+        AssertRC(rc2);
+
+        RTListNodeRemove(&pHandler->Node);
+
+        RTMemFree(pHandler);
+        pHandler = NULL;
+    }
+
+    Assert(RTListIsEmpty(&pStream->State.lstDMAHandlers));
+}
+# endif /* HDA_USE_DMA_ACCESS_HANDLER */
+
+# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+/**
+ * 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) hdaStreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
+{
+    PHDASTREAMTHREADCTX pCtx = (PHDASTREAMTHREADCTX)pvUser;
+    AssertPtr(pCtx);
+
+    PHDASTREAM pStream = pCtx->pStream;
+    AssertPtr(pStream);
+
+    PHDASTREAMSTATEAIO pAIO = &pCtx->pStream->State.AIO;
+
+    ASMAtomicXchgBool(&pAIO->fStarted, true);
+
+    RTThreadUserSignal(hThreadSelf);
+
+    LogFunc(("[SD%RU8]: Started\n", pStream->u8SD));
+
+    for (;;)
+    {
+        int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT);
+        if (RT_FAILURE(rc2))
+            break;
+
+        if (ASMAtomicReadBool(&pAIO->fShutdown))
+            break;
+
+        rc2 = RTCritSectEnter(&pAIO->CritSect);
+        if (RT_SUCCESS(rc2))
+        {
+            if (!pAIO->fEnabled)
+            {
+                RTCritSectLeave(&pAIO->CritSect);
+                continue;
+            }
+
+            hdaStreamUpdate(pStream, false /* fInTimer */);
+
+            int rc3 = RTCritSectLeave(&pAIO->CritSect);
+            AssertRC(rc3);
+        }
+
+        AssertRC(rc2);
+    }
+
+    LogFunc(("[SD%RU8]: Ended\n", pStream->u8SD));
+
+    ASMAtomicXchgBool(&pAIO->fStarted, false);
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Creates the async I/O thread for a specific HDA audio stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA audio stream to create the async I/O thread for.
+ */
+int hdaStreamAsyncIOCreate(PHDASTREAM pStream)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+
+    int rc;
+
+    if (!ASMAtomicReadBool(&pAIO->fStarted))
+    {
+        pAIO->fShutdown = false;
+
+        rc = RTSemEventCreate(&pAIO->Event);
+        if (RT_SUCCESS(rc))
+        {
+            rc = RTCritSectInit(&pAIO->CritSect);
+            if (RT_SUCCESS(rc))
+            {
+                HDASTREAMTHREADCTX Ctx = { pStream->pHDAState, pStream };
+
+                char szThreadName[64];
+                RTStrPrintf2(szThreadName, sizeof(szThreadName), "hdaAIO%RU8", pStream->u8SD);
+
+                rc = RTThreadCreate(&pAIO->Thread, hdaStreamAsyncIOThread, &Ctx,
+                                    0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, szThreadName);
+                if (RT_SUCCESS(rc))
+                    rc = RTThreadUserWait(pAIO->Thread, 10 * 1000 /* 10s timeout */);
+            }
+        }
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    LogFunc(("[SD%RU8]: Returning %Rrc\n", pStream->u8SD, rc));
+    return rc;
+}
+
+/**
+ * Destroys the async I/O thread of a specific HDA audio stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA audio stream to destroy the async I/O thread for.
+ */
+int hdaStreamAsyncIODestroy(PHDASTREAM pStream)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+
+    if (!ASMAtomicReadBool(&pAIO->fStarted))
+        return VINF_SUCCESS;
+
+    ASMAtomicWriteBool(&pAIO->fShutdown, true);
+
+    int rc = hdaStreamAsyncIONotify(pStream);
+    AssertRC(rc);
+
+    int rcThread;
+    rc = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread);
+    LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc, rcThread));
+
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTCritSectDelete(&pAIO->CritSect);
+        AssertRC(rc);
+
+        rc = RTSemEventDestroy(pAIO->Event);
+        AssertRC(rc);
+
+        pAIO->fStarted  = false;
+        pAIO->fShutdown = false;
+        pAIO->fEnabled  = false;
+    }
+
+    LogFunc(("[SD%RU8]: Returning %Rrc\n", pStream->u8SD, rc));
+    return rc;
+}
+
+/**
+ * Lets the stream's async I/O thread know that there is some data to process.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to notify async I/O thread for.
+ */
+int hdaStreamAsyncIONotify(PHDASTREAM pStream)
+{
+    return RTSemEventSignal(pStream->State.AIO.Event);
+}
+
+/**
+ * Locks the async I/O thread of a specific HDA audio stream.
+ *
+ * @param   pStream             HDA stream to lock async I/O thread for.
+ */
+void hdaStreamAsyncIOLock(PHDASTREAM pStream)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+
+    if (!ASMAtomicReadBool(&pAIO->fStarted))
+        return;
+
+    int rc2 = RTCritSectEnter(&pAIO->CritSect);
+    AssertRC(rc2);
+}
+
+/**
+ * Unlocks the async I/O thread of a specific HDA audio stream.
+ *
+ * @param   pStream             HDA stream to unlock async I/O thread for.
+ */
+void hdaStreamAsyncIOUnlock(PHDASTREAM pStream)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+
+    if (!ASMAtomicReadBool(&pAIO->fStarted))
+        return;
+
+    int rc2 = RTCritSectLeave(&pAIO->CritSect);
+    AssertRC(rc2);
+}
+
+/**
+ * Enables (resumes) or disables (pauses) the async I/O thread.
+ *
+ * @param   pStream             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 hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+    ASMAtomicXchgBool(&pAIO->fEnabled, fEnable);
+}
+# endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */
+
+#endif /* IN_RING3 */
Index: /trunk/src/VBox/Devices/Audio/HDAStream.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.h	(revision 67899)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.h	(revision 67899)
@@ -0,0 +1,227 @@
+/* $Id$ */
+/** @file
+ * HDAStream.h - Stream functions for HD Audio.
+ */
+
+/*
+ * Copyright (C) 2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef HDA_STREAM_H
+#define HDA_STREAM_H
+
+#include "DevHDACommon.h"
+
+#include "HDAStreamMap.h"
+#include "HDAStreamPeriod.h"
+
+/*********************************************************************************************************************************
+*   Prototypes                                                                                                                   *
+*********************************************************************************************************************************/
+
+typedef struct HDAMIXERSINK *PHDAMIXERSINK;
+
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+/**
+ * Structure keeping the HDA stream's state for asynchronous I/O.
+ */
+typedef struct HDASTREAMSTATEAIO
+{
+    /** Thread handle for the actual I/O thread. */
+    RTTHREAD              Thread;
+    /** Event for letting the thread know there is some data to process. */
+    RTSEMEVENT            Event;
+    /** Critical section for synchronizing access. */
+    RTCRITSECT            CritSect;
+    /** Started indicator. */
+    volatile bool         fStarted;
+    /** Shutdown indicator. */
+    volatile bool         fShutdown;
+    /** Whether the thread should do any data processing or not. */
+    volatile bool         fEnabled;
+    uint32_t              Padding1;
+} HDASTREAMSTATEAIO, *PHDASTREAMSTATEAIO;
+#endif
+
+#if defined (DEBUG) || defined(HDA_USE_DMA_ACCESS_HANDLER)
+typedef struct HDASTREAMDBGINFO
+{
+    /** Critical section to serialize access if needed. */
+    RTCRITSECT              CritSect;
+    uint32_t                Padding1[2];
+    /** Number of total read accesses. */
+    uint64_t                cReadsTotal;
+    /** Number of total DMA bytes read. */
+    uint64_t                cbReadTotal;
+    /** Timestamp (in ns) of last read access. */
+    uint64_t                tsLastReadNs;
+    /** Number of total write accesses. */
+    uint64_t                cWritesTotal;
+    /** Number of total DMA bytes written. */
+    uint64_t                cbWrittenTotal;
+    /** Number of total write accesses since last iteration (Hz). */
+    uint64_t                cWritesHz;
+    /** Number of total DMA bytes written since last iteration (Hz). */
+    uint64_t                cbWrittenHz;
+    /** Timestamp (in ns) of beginning a new write slot. */
+    uint64_t                tsWriteSlotBegin;
+    /** Number of current silence samples in a (consecutive) row. */
+    uint64_t                csSilence;
+    /** Number of silent samples in a row to consider an audio block as audio gap (silence). */
+    uint64_t                cSilenceThreshold;
+    /** How many bytes to skip in an audio stream before detecting silence.
+     *  (useful for intros and silence at the beginning of a song). */
+    uint64_t                cbSilenceReadMin;
+} HDASTREAMDBGINFO ,*PHDASTREAMDBGINFO;
+#endif /* defined (DEBUG) || defined(HDA_USE_DMA_ACCESS_HANDLER) */
+
+/**
+ * Internal state of a HDA stream.
+ */
+typedef struct HDASTREAMSTATE
+{
+    /** Current BDLE to use. Wraps around to 0 if
+     *  maximum (cBDLE) is reached. */
+    uint16_t                uCurBDLE;
+    /** Flag indicating whether this stream currently is
+     *  in reset mode and therefore not acccessible by the guest. */
+    volatile bool           fInReset;
+    /** Unused, padding. */
+    uint32_t                Padding0;
+    /** Critical section to serialize access. */
+    RTCRITSECT              CritSect;
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+    /** Asynchronous I/O state members. */
+    HDASTREAMSTATEAIO       AIO;
+#endif
+    /** This stream's data mapping. */
+    HDASTREAMMAPPING        Mapping;
+    /** Current BDLE (Buffer Descriptor List Entry). */
+    HDABDLE                 BDLE;
+    /** Circular buffer (FIFO) for holding DMA'ed data. */
+    R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
+    /** Timestamp of the last success DMA data transfer.
+     *  Used to calculate the time actually elapsed between two transfers. */
+    uint64_t                uTimerTS;
+    /** The stream's period. Need for timing. */
+    HDASTREAMPERIOD         Period;
+    /** The stream's current configuration.
+     *  Should match SDFMT. */
+    PDMAUDIOSTREAMCFG       strmCfg;
+#ifdef HDA_USE_DMA_ACCESS_HANDLER
+    /** List of DMA handlers. */
+    RTLISTANCHORR3          lstDMAHandlers;
+#endif
+    /** Unused, padding. */
+    uint8_t                 Padding1[3];
+} HDASTREAMSTATE, *PHDASTREAMSTATE;
+
+/**
+ * Structure for keeping a HDA stream (SDI / SDO).
+ *
+ * Note: This HDA stream has nothing to do with a regular audio stream handled
+ * by the audio connector or the audio mixer. This HDA stream is a serial data in/out
+ * stream (SDI/SDO) defined in hardware and can contain multiple audio streams
+ * in one single SDI/SDO (interleaving streams).
+ *
+ * How a specific SDI/SDO is mapped to our internal audio streams relies on the
+ * stream channel mappings.
+ *
+ * Contains only register values which do *not* change until a
+ * stream reset occurs.
+ */
+typedef struct HDASTREAM
+{
+    /** Stream descriptor number (SDn). */
+    uint8_t                  u8SD;
+    uint8_t                  Padding0[7];
+    /** DMA base address (SDnBDPU - SDnBDPL). */
+    uint64_t                 u64BDLBase;
+    /** Cyclic Buffer Length (SDnCBL).
+     *  Represents the size of the ring buffer. */
+    uint32_t                 u32CBL;
+    /** Format (SDnFMT). */
+    uint16_t                 u16FMT;
+    /** FIFO Size (FIFOS).
+     *  Maximum number of bytes that may have been DMA'd into
+     *  memory but not yet transmitted on the link. */
+    uint16_t                 u16FIFOS;
+    /** FIFO Watermark. */
+    uint16_t                 u16FIFOW;
+    /** Last Valid Index (SDnLVI). */
+    uint16_t                 u16LVI;
+    uint16_t                 Padding1[2];
+    /** Pointer to the HDA state this stream is attached to. */
+    R3PTRTYPE(PHDASTATE)     pHDAState;
+    /** Pointer to HDA sink this stream is attached to. */
+    R3PTRTYPE(PHDAMIXERSINK) pMixSink;
+    /** Internal state of this stream. */
+    HDASTREAMSTATE           State;
+#ifdef DEBUG
+    /** Debug information. */
+    HDASTREAMDBGINFO         Dbg;
+#endif
+} HDASTREAM, *PHDASTREAM;
+
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+/**
+ * Structure for keeping a HDA stream thread context.
+ */
+typedef struct HDASTREAMTHREADCTX
+{
+    PHDASTATE  pThis;
+    PHDASTREAM pStream;
+} HDASTREAMTHREADCTX, *PHDASTREAMTHREADCTX;
+#endif
+
+#ifdef IN_RING3
+
+/** @name Stream functions.
+ * @{
+ */
+int           hdaStreamCreate(PHDASTREAM pStream, PHDASTATE pThis);
+void          hdaStreamDestroy(PHDASTREAM pStream);
+int           hdaStreamInit(PHDASTREAM pStream, uint8_t uSD);
+void          hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD);
+int           hdaStreamEnable(PHDASTREAM pStream, bool fEnable);
+uint32_t      hdaStreamGetUsed(PHDASTREAM pStream);
+uint32_t      hdaStreamGetFree(PHDASTREAM pStream);
+int           hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax);
+uint32_t      hdaStreamUpdateLPIB(PHDASTREAM pStream, uint32_t u32LPIB);
+void          hdaStreamLock(PHDASTREAM pStream);
+void          hdaStreamUnlock(PHDASTREAM pStream);
+int           hdaStreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead);
+int           hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten);
+void          hdaStreamUpdate(PHDASTREAM pStream, bool fAsync);
+# ifdef HDA_USE_DMA_ACCESS_HANDLER
+bool          hdaStreamRegisterDMAHandlers(PHDASTREAM pStream);
+void          hdaStreamUnregisterDMAHandlers(PHDASTREAM pStream);
+# endif /* HDA_USE_DMA_ACCESS_HANDLER */
+/** @} */
+
+/** @name Async I/O stream functions.
+ * @{
+ */
+# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+int           hdaStreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser);
+int           hdaStreamAsyncIOCreate(PHDASTREAM pStream);
+int           hdaStreamAsyncIODestroy(PHDASTREAM pStream);
+int           hdaStreamAsyncIONotify(PHDASTREAM pStream);
+void          hdaStreamAsyncIOLock(PHDASTREAM pStream);
+void          hdaStreamAsyncIOUnlock(PHDASTREAM pStream);
+void          hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable);
+# endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */
+/** @} */
+
+#endif /* IN_RING3 */
+
+#endif /* !HDA_STREAM_H */
+
Index: /trunk/src/VBox/Devices/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Devices/Makefile.kmk	(revision 67898)
+++ /trunk/src/VBox/Devices/Makefile.kmk	(revision 67899)
@@ -596,5 +596,7 @@
 	Audio/DevSB16.cpp \
 	Audio/DevHDA.cpp \
+	Audio/DevHDACommon.cpp \
 	Audio/HDACodec.cpp \
+	Audio/HDAStream.cpp \
 	Audio/HDAStreamChannel.cpp \
 	Audio/HDAStreamMap.cpp \
