diff options
author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2021-06-24 12:30:53 +0000 |
---|---|---|
committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2021-06-24 12:30:53 +0000 |
commit | 0705eb11f4ae371f6a36deb7ffd5a4e07d338c67 (patch) | |
tree | 81decaf6bc5f0a4a8c178f1d38d19948d863c979 /src/VBox/Devices/Audio | |
parent | 891b234764b207fd6124500ed04501522c9e5083 (diff) | |
download | VirtualBox-svn-0705eb11f4ae371f6a36deb7ffd5a4e07d338c67.tar.gz |
DevHda: Merged DevHdaCommon.h into DevHda.h and mostly likewise with the corresponding code. bugref:9890
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@89887 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/Devices/Audio')
-rw-r--r-- | src/VBox/Devices/Audio/DevHda.cpp | 135 | ||||
-rw-r--r-- | src/VBox/Devices/Audio/DevHda.h | 530 | ||||
-rw-r--r-- | src/VBox/Devices/Audio/DevHdaCodec.cpp | 2 | ||||
-rw-r--r-- | src/VBox/Devices/Audio/DevHdaCommon.cpp | 373 | ||||
-rw-r--r-- | src/VBox/Devices/Audio/DevHdaCommon.h | 591 | ||||
-rw-r--r-- | src/VBox/Devices/Audio/DevHdaStream.cpp | 159 | ||||
-rw-r--r-- | src/VBox/Devices/Audio/DevHdaStream.h | 8 |
7 files changed, 822 insertions, 976 deletions
diff --git a/src/VBox/Devices/Audio/DevHda.cpp b/src/VBox/Devices/Audio/DevHda.cpp index b3c975fce60..2f1c4deaf5c 100644 --- a/src/VBox/Devices/Audio/DevHda.cpp +++ b/src/VBox/Devices/Audio/DevHda.cpp @@ -400,7 +400,17 @@ const HDAREGDESC g_aHdaRegMap[HDA_NUM_REGS] = HDA_REG_MAP_DEF_STREAM(7, SD7) }; -const HDAREGALIAS g_aHdaRegAliases[] = +/** + * HDA register aliases (HDA spec 3.3.45). + * @remarks Sorted by offReg. + */ +static struct HDAREGALIAS +{ + /** The alias register offset. */ + uint32_t offReg; + /** The register index. */ + int idxAlias; +} const g_aHdaRegAliases[] = { { 0x2030, HDA_REG_WALCLK }, { 0x2084, HDA_REG_SD0LPIB }, @@ -498,6 +508,94 @@ static uint32_t const g_afMasks[5] = }; + +/** + * Returns a new INTSTS value based on the current device state. + * + * @returns Determined INTSTS register value. + * @param pThis The shared HDA device state. + * + * @remarks This function does *not* set INTSTS! + */ +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)) + { + intSts |= HDA_INTSTS_CIS; /* Set the Controller Interrupt Status (CIS). */ + } + + /* Check SDIN State Change Status Flags. */ + 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; +} + + +/** + * Processes (asserts/deasserts) the HDA interrupt according to the current state. + * + * @param pDevIns The device instance. + * @param pThis The shared HDA device state. + * @param pszSource Caller information. + */ +#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING) +void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource) +#else +void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis) +#endif +{ + uint32_t uIntSts = hdaGetINTSTS(pThis); + + HDA_REG(pThis, INTSTS) = uIntSts; + + /* 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. + */ + /* Global Interrupt Enable (GIE) set? */ + if ( (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE) + && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK))) + { + Log3Func(("Asserted (%s)\n", pszSource)); + + PDMDevHlpPCISetIrq(pDevIns, 0, 1 /* Assert */); + pThis->u8IRQL = 1; + +#ifdef DEBUG + pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS(); + pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs; +#endif + } + else + { + Log3Func(("Deasserted (%s)\n", pszSource)); + + PDMDevHlpPCISetIrq(pDevIns, 0, 0 /* Deassert */); + pThis->u8IRQL = 0; + } +} + + /** * Looks up a register at the exact offset given by @a offReg. * @@ -1551,6 +1649,29 @@ static VBOXSTRICTRC hdaRegWriteSDLVI(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32 return hdaRegWriteU16(pDevIns, pThis, iReg, u32Value); } +/** + * Calculates the number of bytes of a FIFOW register. + * + * @return Number of bytes of a given FIFOW register. + * @param u16RegFIFOW FIFOW register to convert. + */ +uint8_t hdaSDFIFOWToBytes(uint16_t u16RegFIFOW) +{ + uint32_t cb; + switch (u16RegFIFOW) + { + case HDA_SDFIFOW_8B: cb = 8; break; + case HDA_SDFIFOW_16B: cb = 16; break; + case HDA_SDFIFOW_32B: cb = 32; break; + default: + AssertFailedStmt(cb = 32); /* Paranoia. */ + break; + } + + Assert(RT_IS_POWER_OF_TWO(cb)); + return cb; +} + static VBOXSTRICTRC hdaRegWriteSDFIFOW(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) { size_t const idxStream = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg); @@ -2158,7 +2279,7 @@ static int hdaR3MixerAddDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER { int rc = VINF_SUCCESS; - PHDASTREAM pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkLineIn); + PHDASTREAM pStream = pThisCC->SinkLineIn.pStreamShared; if ( pStream && AudioHlpStreamCfgIsValid(&pStream->State.Cfg)) { @@ -2168,7 +2289,7 @@ static int hdaR3MixerAddDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER } # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN - pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkMicIn); + pStream = pThisCC->SinkMicIn.pStreamShared; if ( pStream && AudioHlpStreamCfgIsValid(&pStream->State.Cfg)) { @@ -2178,7 +2299,7 @@ static int hdaR3MixerAddDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER } # endif - pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkFront); + pStream = pThisCC->SinkFront.pStreamShared; if ( pStream && AudioHlpStreamCfgIsValid(&pStream->State.Cfg)) { @@ -2188,7 +2309,7 @@ static int hdaR3MixerAddDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER } # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND - pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkCenterLFE); + pStream = pThisCC->SinkCenterLFE.pStreamShared; if ( pStream && AudioHlpStreamCfgIsValid(&pStream->State.Cfg)) { @@ -2197,7 +2318,7 @@ static int hdaR3MixerAddDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER rc = rc2; } - pStream = hdaR3GetSharedStreamFromSink(&pThisCC->SinkRear); + pStream = pThisCC->SinkRear.pStreamShared; if ( pStream && AudioHlpStreamCfgIsValid(&pStream->State.Cfg)) { @@ -4856,7 +4977,7 @@ static DECLCALLBACK(int) hdaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++) { struct HDAREGDESC const *pReg = &g_aHdaRegMap[i]; - struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL; + struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL; /* binary search order. */ AssertReleaseMsg(!pNextReg || pReg->offset + pReg->size <= pNextReg->offset, diff --git a/src/VBox/Devices/Audio/DevHda.h b/src/VBox/Devices/Audio/DevHda.h index 08339d943b1..54a4938fd11 100644 --- a/src/VBox/Devices/Audio/DevHda.h +++ b/src/VBox/Devices/Audio/DevHda.h @@ -68,16 +68,506 @@ typedef struct HDASTREAMR3 *PHDASTREAMR3; typedef struct HDASTATE *PHDASTATE; /** Pointer to a ring-3 HDA device state. */ typedef struct HDASTATER3 *PHDASTATER3; +/** Pointer to an HDA mixer sink definition (ring-3). */ +typedef struct HDAMIXERSINK *PHDAMIXERSINK; /* * The rest of the headers. */ -#include "DevHdaCommon.h" #include "DevHdaStream.h" #include "DevHdaCodec.h" + +/** @name Stream counts. + * + * 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 + + +/** Read callback. */ +typedef VBOXSTRICTRC FNHDAREGREAD(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +/** Write callback. */ +typedef VBOXSTRICTRC FNHDAREGWRITE(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); + +/** + * HDA register descriptor. + */ +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_F_XXX. These are used to + * specify the handling (read/write) policy of the register. */ + uint32_t fFlags; + /** Read callback. */ + FNHDAREGREAD *pfnRead; + /** Write callback. */ + FNHDAREGWRITE *pfnWrite; + /** Index into the register storage array. + * @todo r=bird: Bad structure layout. Move up before pfnRead. */ + uint32_t mem_idx; + /** Abbreviated name. */ + const char *abbrev; + /** Descripton. */ + const char *desc; +} HDAREGDESC; + +extern const HDAREGDESC g_aHdaRegMap[HDA_NUM_REGS]; + + +/** + * ICH6 datasheet defines limits for FIFOS registers (18.2.39). + * Formula: size - 1 + * Other values not listed are not supported. + */ + +/** 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 + +/* + * 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 */ + +#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 +#define HDA_CORBSIZE_SZ_CAP 0xF0 +#define HDA_CORBSIZE_SZ 0x3 + +/** Number of CORB buffer entries. */ +#define HDA_CORB_SIZE 256 +/** CORB element size (in bytes). */ +#define HDA_CORB_ELEMENT_SIZE 4 +/** Number of RIRB buffer entries. */ +#define HDA_RIRB_SIZE 256 +/** RIRB element size (in bytes). */ +#define HDA_RIRB_ELEMENT_SIZE 8 + +#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 + +/** Maximum number of Response Interrupts. */ +#define HDA_MAX_RINTCNT 256 + +#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 +#define HDA_SDFMT_NON_PCM_MASK 0x1 +#define HDA_SDFMT_BASE_RATE_SHIFT 14 +#define HDA_SDFMT_BASE_RATE_MASK 0x1 +#define HDA_SDFMT_MULT_SHIFT 11 +#define HDA_SDFMT_MULT_MASK 0x7 +#define HDA_SDFMT_DIV_SHIFT 8 +#define HDA_SDFMT_DIV_MASK 0x7 +#define HDA_SDFMT_BITS_SHIFT 4 +#define HDA_SDFMT_BITS_MASK 0x7 +#define HDA_SDFMT_CHANNELS_MASK 0xF + +#define HDA_SDFMT_TYPE RT_BIT(15) +#define HDA_SDFMT_TYPE_PCM (0) +#define HDA_SDFMT_TYPE_NON_PCM (1) + +#define HDA_SDFMT_BASE RT_BIT(14) +#define HDA_SDFMT_BASE_48KHZ (0) +#define HDA_SDFMT_BASE_44KHZ (1) + +#define HDA_SDFMT_MULT_1X (0) +#define HDA_SDFMT_MULT_2X (1) +#define HDA_SDFMT_MULT_3X (2) +#define HDA_SDFMT_MULT_4X (3) + +#define HDA_SDFMT_DIV_1X (0) +#define HDA_SDFMT_DIV_2X (1) +#define HDA_SDFMT_DIV_3X (2) +#define HDA_SDFMT_DIV_4X (3) +#define HDA_SDFMT_DIV_5X (4) +#define HDA_SDFMT_DIV_6X (5) +#define HDA_SDFMT_DIV_7X (6) +#define HDA_SDFMT_DIV_8X (7) + +#define HDA_SDFMT_8_BIT (0) +#define HDA_SDFMT_16_BIT (1) +#define HDA_SDFMT_20_BIT (2) +#define HDA_SDFMT_24_BIT (3) +#define HDA_SDFMT_32_BIT (4) + +#define HDA_SDFMT_CHAN_MONO (0) +#define HDA_SDFMT_CHAN_STEREO (1) + +/** Emits a SDnFMT register format. + * Also being used in the codec's converter format. */ +#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan) \ + ( (((_afNonPCM) & HDA_SDFMT_NON_PCM_MASK) << HDA_SDFMT_NON_PCM_SHIFT) \ + | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \ + | (((_aMult) & HDA_SDFMT_MULT_MASK) << HDA_SDFMT_MULT_SHIFT) \ + | (((_aDiv) & HDA_SDFMT_DIV_MASK) << HDA_SDFMT_DIV_SHIFT) \ + | (((_aBits) & HDA_SDFMT_BITS_MASK) << HDA_SDFMT_BITS_SHIFT) \ + | ( (_aChan) & HDA_SDFMT_CHANNELS_MASK)) + +/** Interrupt on completion (IOC) flag. */ +#define HDA_BDLE_F_IOC RT_BIT(0) + + +/** + * 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 u64BufAddr; + /** 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. */ + + + /** * HDA mixer sink definition (ring-3). * @@ -97,8 +587,6 @@ typedef struct HDAMIXERSINK /** Pointer to the actual audio mixer sink. */ R3PTRTYPE(PAUDMIXSINK) pMixSink; } HDAMIXERSINK; -/** Pointer to an HDA mixer sink definition (ring-3). */ -typedef HDAMIXERSINK *PHDAMIXERSINK; /** * Mapping a stream tag to an HDA stream (ring-3). @@ -302,5 +790,41 @@ typedef struct HDASTATER3 /** Pointer to the context specific HDA state (HDASTATER3 or HDASTATER0). */ typedef CTX_SUFF(PHDASTATE) PHDASTATECC; + +/** @def HDA_PROCESS_INTERRUPT + * Wrapper around hdaProcessInterrupt that supplies the source function name + * string in logging builds. */ +#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING) +void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource); +# define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis) hdaProcessInterrupt((a_pDevIns), (a_pThis), __FUNCTION__) +#else +void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis); +# define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis) hdaProcessInterrupt((a_pDevIns), (a_pThis)) +#endif + +/** + * Returns the audio direction of a specified stream descriptor. + * + * The register layout specifies that input streams (SDI) come first, + * followed by the output streams (SDO). So every stream ID below HDA_MAX_SDI + * is an input stream, whereas everything >= HDA_MAX_SDI is an output stream. + * + * @note SDnFMT register does not provide that information, so we have to judge + * for ourselves. + * + * @return Audio direction. + * @param uSD The stream number. + */ +DECLINLINE(PDMAUDIODIR) hdaGetDirFromSD(uint8_t uSD) +{ + if (uSD < HDA_MAX_SDI) + return PDMAUDIODIR_IN; + AssertReturn(uSD < HDA_MAX_STREAMS, PDMAUDIODIR_UNKNOWN); + return PDMAUDIODIR_OUT; +} + +/* Used by hdaR3StreamSetUp: */ +uint8_t hdaSDFIFOWToBytes(uint16_t u16RegFIFOW); + #endif /* !VBOX_INCLUDED_SRC_Audio_DevHda_h */ diff --git a/src/VBox/Devices/Audio/DevHdaCodec.cpp b/src/VBox/Devices/Audio/DevHdaCodec.cpp index cc0cba69f61..ef015f10cbe 100644 --- a/src/VBox/Devices/Audio/DevHdaCodec.cpp +++ b/src/VBox/Devices/Audio/DevHdaCodec.cpp @@ -40,8 +40,6 @@ #include "VBoxDD.h" #include "AudioMixer.h" #include "DevHda.h" -#include "DevHdaCodec.h" -#include "DevHdaCommon.h" /********************************************************************************************************************************* diff --git a/src/VBox/Devices/Audio/DevHdaCommon.cpp b/src/VBox/Devices/Audio/DevHdaCommon.cpp deleted file mode 100644 index 241d56bea14..00000000000 --- a/src/VBox/Devices/Audio/DevHdaCommon.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* $Id$ */ -/** @file - * Intel HD Audio Controller Emulation - Common stuff. - * - * @todo r=bird: Shared with whom exactly? - */ - -/* - * Copyright (C) 2017-2020 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 <iprt/assert.h> -#include <iprt/errcore.h> -#include <iprt/time.h> - -#include <VBox/AssertGuest.h> -#include <VBox/vmm/pdmaudioinline.h> - -#include <VBox/log.h> - -#include "DevHda.h" -#include "DevHdaCommon.h" - - - -/** - * Processes (de/asserts) the interrupt according to the HDA's current state. - * - * @param pDevIns The device instance. - * @param pThis The shared HDA device state. - * @param pszSource Caller information. - */ -#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING) -void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource) -#else -void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis) -#endif -{ - uint32_t uIntSts = hdaGetINTSTS(pThis); - - HDA_REG(pThis, INTSTS) = uIntSts; - - /* 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. - */ - /* Global Interrupt Enable (GIE) set? */ - if ( (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE) - && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK))) - { - Log3Func(("Asserted (%s)\n", pszSource)); - - PDMDevHlpPCISetIrq(pDevIns, 0, 1 /* Assert */); - pThis->u8IRQL = 1; - -#ifdef DEBUG - pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS(); - pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs; -#endif - } - else - { - Log3Func(("Deasserted (%s)\n", pszSource)); - - PDMDevHlpPCISetIrq(pDevIns, 0, 0 /* Deassert */); - pThis->u8IRQL = 0; - } -} - -/** - * Retrieves the number of bytes of a FIFOW register. - * - * @return Number of bytes of a given FIFOW register. - * @param u16RegFIFOW FIFOW register to convert. - */ -uint8_t hdaSDFIFOWToBytes(uint16_t u16RegFIFOW) -{ - uint32_t cb; - switch (u16RegFIFOW) - { - case HDA_SDFIFOW_8B: cb = 8; break; - case HDA_SDFIFOW_16B: cb = 16; break; - case HDA_SDFIFOW_32B: cb = 32; break; - default: - AssertFailedStmt(cb = 32); /* Paranoia. */ - break; - } - - Assert(RT_IS_POWER_OF_TWO(cb)); - return cb; -} - -#ifdef IN_RING3 -/** - * Returns the default (mixer) sink from a given SD#. - * Returns NULL if no sink is found. - * - * @return PHDAMIXERSINK - * @param pThisCC The ring-3 HDA device state. - * @param uSD SD# to return mixer sink for. - * NULL if not found / handled. - */ -PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATER3 pThisCC, uint8_t uSD) -{ - if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN) - { - const uint8_t uFirstSDI = 0; - - if (uSD == uFirstSDI) /* First SDI. */ - return &pThisCC->SinkLineIn; -# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN - if (uSD == uFirstSDI + 1) - return &pThisCC->SinkMicIn; -# else - /* If we don't have a dedicated Mic-In sink, use the always present Line-In sink. */ - return &pThisCC->SinkLineIn; -# endif - } - else - { - const uint8_t uFirstSDO = HDA_MAX_SDI; - - if (uSD == uFirstSDO) - return &pThisCC->SinkFront; -# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND - if (uSD == uFirstSDO + 1) - return &pThisCC->SinkCenterLFE; - if (uSD == uFirstSDO + 2) - return &pThisCC->SinkRear; -# endif - } - - return NULL; -} -#endif /* IN_RING3 */ - -/** - * 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. - */ -PDMAUDIODIR hdaGetDirFromSD(uint8_t uSD) -{ - AssertReturn(uSD < HDA_MAX_STREAMS, PDMAUDIODIR_UNKNOWN); - - if (uSD < HDA_MAX_SDI) - return PDMAUDIODIR_IN; - - return PDMAUDIODIR_OUT; -} - -/** - * Returns the HDA stream of specified stream descriptor number. - * - * @return Pointer to HDA stream, or NULL if none found. - */ -PHDASTREAM hdaGetStreamFromSD(PHDASTATE pThis, uint8_t uSD) -{ - AssertPtr(pThis); - ASSERT_GUEST_MSG_RETURN(uSD < HDA_MAX_STREAMS, ("uSD=%u (%#x)\n", uSD, uSD), NULL); - return &pThis->aStreams[uSD]; -} - -#ifdef IN_RING3 - -/** - * Returns the HDA stream of specified HDA sink. - * - * @return Pointer to HDA stream, or NULL if none found. - */ -PHDASTREAMR3 hdaR3GetR3StreamFromSink(PHDAMIXERSINK pSink) -{ - AssertPtrReturn(pSink, NULL); - - /** @todo Do something with the channel mapping here? */ - return pSink->pStreamR3; -} - - -/** - * Returns the HDA stream of specified HDA sink. - * - * @return Pointer to HDA stream, or NULL if none found. - */ -PHDASTREAM hdaR3GetSharedStreamFromSink(PHDAMIXERSINK pSink) -{ - AssertPtrReturn(pSink, NULL); - - /** @todo Do something with the channel mapping here? */ - return pSink->pStreamShared; -} - -#endif /* IN_RING3 */ - -/** - * Returns a new INTSTS value based on the current device state. - * - * @returns Determined INTSTS register value. - * @param pThis The shared HDA device state. - * - * @remark This function does *not* set INTSTS! - */ -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)) - { - intSts |= HDA_INTSTS_CIS; /* Set the Controller Interrupt Status (CIS). */ - } - - /* Check SDIN State Change Status Flags. */ - 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; -} - -#ifdef IN_RING3 - -/** - * Converts an HDA stream's SDFMT register into a given PCM properties structure. - * - * @returns VBox status code. - * @param u16SDFMT The HDA stream's SDFMT value to convert. - * @param pProps PCM properties structure to hold converted result on success. - */ -int hdaR3SDFMTToPCMProps(uint16_t u16SDFMT, 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(u16SDFMT, HDA_SDFMT_BASE_RATE_MASK, HDA_SDFMT_BASE_RATE_SHIFT) - ? 44100 : 48000; - uint32_t u32HzMult = 1; - uint32_t u32HzDiv = 1; - - switch (EXTRACT_VALUE(u16SDFMT, 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(u16SDFMT, HDA_SDFMT_MULT_MASK, HDA_SDFMT_MULT_SHIFT))); - rc = VERR_NOT_SUPPORTED; - break; - } - switch (EXTRACT_VALUE(u16SDFMT, 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(u16SDFMT, HDA_SDFMT_DIV_MASK, HDA_SDFMT_DIV_SHIFT))); - rc = VERR_NOT_SUPPORTED; - break; - } - - uint8_t cbSample = 0; - switch (EXTRACT_VALUE(u16SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)) - { - case 0: - cbSample = 1; - break; - case 1: - cbSample = 2; - break; - case 4: - cbSample = 4; - break; - default: - AssertMsgFailed(("Unsupported bits per sample %x\n", - EXTRACT_VALUE(u16SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))); - rc = VERR_NOT_SUPPORTED; - break; - } - - if (RT_SUCCESS(rc)) - { - PDMAudioPropsInit(pProps, cbSample, true /*fSigned*/, (u16SDFMT & 0xf) + 1 /*cChannels*/, u32Hz * u32HzMult / u32HzDiv); - /** @todo is there anything we need to / can do about channel assignments? */ - } - -# undef EXTRACT_VALUE - return rc; -} - -# ifdef LOG_ENABLED -void hdaR3BDLEDumpAll(PPDMDEVINS pDevIns, PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE) -{ - LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE)); - if (!u64BDLBase) - return; - - uint32_t cbBDLE = 0; - for (uint16_t i = 0; i < cBDLE; i++) - { - HDABDLEDESC bd; - PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd)); - - LogFunc(("\t#%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n", - i, bd.u64BufAddr, bd.u32BufSize, bd.fFlags & HDA_BDLE_F_IOC)); - - cbBDLE += bd.u32BufSize; - } - - LogFlowFunc(("Total: %RU32 bytes\n", cbBDLE)); - - if (!pThis->u64DPBase) /* No DMA base given? Bail out. */ - return; - - LogFlowFunc(("DMA counters:\n")); - - for (int i = 0; i < cBDLE; i++) - { - uint32_t uDMACnt; - PDMDevHlpPhysRead(pDevIns, (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)), - &uDMACnt, sizeof(uDMACnt)); - - LogFlowFunc(("\t#%03d DMA @ 0x%x\n", i , uDMACnt)); - } -} -# endif /* LOG_ENABLED */ - -#endif /* IN_RING3 */ diff --git a/src/VBox/Devices/Audio/DevHdaCommon.h b/src/VBox/Devices/Audio/DevHdaCommon.h deleted file mode 100644 index 6b6c5d6aada..00000000000 --- a/src/VBox/Devices/Audio/DevHdaCommon.h +++ /dev/null @@ -1,591 +0,0 @@ -/* $Id$ */ -/** @file - * Intel HD Audio Controller Emulation - Common stuff. - * - * @todo r=bird: Wtf is this? Do we have some other HDA implementations - * that I'm not aware of that shares this code? - */ - -/* - * Copyright (C) 2016-2020 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 VBOX_INCLUDED_SRC_Audio_DevHdaCommon_h -#define VBOX_INCLUDED_SRC_Audio_DevHdaCommon_h -#ifndef RT_WITHOUT_PRAGMA_ONCE -# pragma once -#endif - -#ifndef VBOX_INCLUDED_SRC_Audio_DevHda_h -# error "Only include DevHda.h!" -#endif - -#include "AudioMixer.h" -#include <VBox/log.h> /* LOG_ENABLED */ - - -/** Read callback. */ -typedef VBOXSTRICTRC FNHDAREGREAD(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); -/** Write callback. */ -typedef VBOXSTRICTRC FNHDAREGWRITE(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - -/** - * HDA register descriptor. - * - * 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_F_XXX. These are used to - * specify the handling (read/write) policy of the register. */ - uint32_t fFlags; - /** Read callback. */ - FNHDAREGREAD *pfnRead; - /** Write callback. */ - FNHDAREGWRITE *pfnWrite; - /** Index into the register storage array. */ - uint32_t mem_idx; - /** Abbreviated name. */ - const char *abbrev; - /** Descripton. */ - const char *desc; -} HDAREGDESC; -/** Pointer to a a const HDA register descriptor. */ -typedef HDAREGDESC const *PCHDAREGDESC; - -/** - * 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; - -/** - * 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 - -/** - * ICH6 datasheet defines limits for FIFOS registers (18.2.39). - * Formula: size - 1 - * Other values not listed are not supported. - */ - -/** 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 */ - -#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 -#define HDA_CORBSIZE_SZ_CAP 0xF0 -#define HDA_CORBSIZE_SZ 0x3 - -/** Number of CORB buffer entries. */ -#define HDA_CORB_SIZE 256 -/** CORB element size (in bytes). */ -#define HDA_CORB_ELEMENT_SIZE 4 -/** Number of RIRB buffer entries. */ -#define HDA_RIRB_SIZE 256 -/** RIRB element size (in bytes). */ -#define HDA_RIRB_ELEMENT_SIZE 8 - -#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 - -/** Maximum number of Response Interrupts. */ -#define HDA_MAX_RINTCNT 256 - -#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 -#define HDA_SDFMT_NON_PCM_MASK 0x1 -#define HDA_SDFMT_BASE_RATE_SHIFT 14 -#define HDA_SDFMT_BASE_RATE_MASK 0x1 -#define HDA_SDFMT_MULT_SHIFT 11 -#define HDA_SDFMT_MULT_MASK 0x7 -#define HDA_SDFMT_DIV_SHIFT 8 -#define HDA_SDFMT_DIV_MASK 0x7 -#define HDA_SDFMT_BITS_SHIFT 4 -#define HDA_SDFMT_BITS_MASK 0x7 -#define HDA_SDFMT_CHANNELS_MASK 0xF - -#define HDA_SDFMT_TYPE RT_BIT(15) -#define HDA_SDFMT_TYPE_PCM (0) -#define HDA_SDFMT_TYPE_NON_PCM (1) - -#define HDA_SDFMT_BASE RT_BIT(14) -#define HDA_SDFMT_BASE_48KHZ (0) -#define HDA_SDFMT_BASE_44KHZ (1) - -#define HDA_SDFMT_MULT_1X (0) -#define HDA_SDFMT_MULT_2X (1) -#define HDA_SDFMT_MULT_3X (2) -#define HDA_SDFMT_MULT_4X (3) - -#define HDA_SDFMT_DIV_1X (0) -#define HDA_SDFMT_DIV_2X (1) -#define HDA_SDFMT_DIV_3X (2) -#define HDA_SDFMT_DIV_4X (3) -#define HDA_SDFMT_DIV_5X (4) -#define HDA_SDFMT_DIV_6X (5) -#define HDA_SDFMT_DIV_7X (6) -#define HDA_SDFMT_DIV_8X (7) - -#define HDA_SDFMT_8_BIT (0) -#define HDA_SDFMT_16_BIT (1) -#define HDA_SDFMT_20_BIT (2) -#define HDA_SDFMT_24_BIT (3) -#define HDA_SDFMT_32_BIT (4) - -#define HDA_SDFMT_CHAN_MONO (0) -#define HDA_SDFMT_CHAN_STEREO (1) - -/** Emits a SDnFMT register format. - * Also being used in the codec's converter format. */ -#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan) \ - ( (((_afNonPCM) & HDA_SDFMT_NON_PCM_MASK) << HDA_SDFMT_NON_PCM_SHIFT) \ - | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \ - | (((_aMult) & HDA_SDFMT_MULT_MASK) << HDA_SDFMT_MULT_SHIFT) \ - | (((_aDiv) & HDA_SDFMT_DIV_MASK) << HDA_SDFMT_DIV_SHIFT) \ - | (((_aBits) & HDA_SDFMT_BITS_MASK) << HDA_SDFMT_BITS_SHIFT) \ - | ( (_aChan) & HDA_SDFMT_CHANNELS_MASK)) - -/** Interrupt on completion (IOC) flag. */ -#define HDA_BDLE_F_IOC RT_BIT(0) - - - -/** Pointer to a shared HDA state. */ -typedef struct HDASTATE *PHDASTATE; -/** Pointer to a HDA stream state. */ -typedef struct HDASTREAM *PHDASTREAM; -/** Pointer to a mixer sink. */ -typedef struct HDAMIXERSINK *PHDAMIXERSINK; - - -/** - * 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 u64BufAddr; - /** 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. */ - - -/** @name Object lookup functions. - * @{ - */ -#ifdef IN_RING3 -PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATER3 pThisCC, uint8_t uSD); -#endif -PDMAUDIODIR hdaGetDirFromSD(uint8_t uSD); -//PHDASTREAM hdaGetStreamFromSD(PHDASTATER3 pThisCC, uint8_t uSD); -#ifdef IN_RING3 -PHDASTREAMR3 hdaR3GetR3StreamFromSink(PHDAMIXERSINK pSink); -PHDASTREAM hdaR3GetSharedStreamFromSink(PHDAMIXERSINK pSink); -#endif -/** @} */ - -/** @name Interrupt functions. - * @{ - */ -#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING) -void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource); -# define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis) hdaProcessInterrupt((a_pDevIns), (a_pThis), __FUNCTION__) -#else -void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis); -# define HDA_PROCESS_INTERRUPT(a_pDevIns, a_pThis) hdaProcessInterrupt((a_pDevIns), (a_pThis)) -#endif -/** @} */ - -/** @name Register utility functions. - * @{ */ -uint8_t hdaSDFIFOWToBytes(uint16_t u16RegFIFOW); -/** @} */ - -/** @name Register functions. - * @{ - */ -uint32_t hdaGetINTSTS(PHDASTATE pThis); -#ifdef IN_RING3 -int hdaR3SDFMTToPCMProps(uint16_t u16SDFMT, PPDMAUDIOPCMPROPS pProps); -#endif /* IN_RING3 */ -/** @} */ - -/** @name BDLE (Buffer Descriptor List Entry) functions. - * @{ - */ -#ifdef IN_RING3 -# ifdef LOG_ENABLED -void hdaR3BDLEDumpAll(PPDMDEVINS pDevIns, PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE); -# endif -#endif /* IN_RING3 */ -/** @} */ - -#endif /* !VBOX_INCLUDED_SRC_Audio_DevHdaCommon_h */ - diff --git a/src/VBox/Devices/Audio/DevHdaStream.cpp b/src/VBox/Devices/Audio/DevHdaStream.cpp index 763564cf5b7..c5799fe59ed 100644 --- a/src/VBox/Devices/Audio/DevHdaStream.cpp +++ b/src/VBox/Devices/Audio/DevHdaStream.cpp @@ -208,6 +208,122 @@ void hdaR3StreamDestroy(PHDASTREAMR3 pStreamR3) /** + * Converts an HDA stream's SDFMT register into a given PCM properties structure. + * + * @returns VBox status code. + * @param u16SDFMT The HDA stream's SDFMT value to convert. + * @param pProps PCM properties structure to hold converted result on success. + */ +int hdaR3SDFMTToPCMProps(uint16_t u16SDFMT, 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(u16SDFMT, HDA_SDFMT_BASE_RATE_MASK, HDA_SDFMT_BASE_RATE_SHIFT) + ? 44100 : 48000; + uint32_t u32HzMult = 1; + uint32_t u32HzDiv = 1; + + switch (EXTRACT_VALUE(u16SDFMT, 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(u16SDFMT, HDA_SDFMT_MULT_MASK, HDA_SDFMT_MULT_SHIFT))); + rc = VERR_NOT_SUPPORTED; + break; + } + switch (EXTRACT_VALUE(u16SDFMT, 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(u16SDFMT, HDA_SDFMT_DIV_MASK, HDA_SDFMT_DIV_SHIFT))); + rc = VERR_NOT_SUPPORTED; + break; + } + + uint8_t cbSample = 0; + switch (EXTRACT_VALUE(u16SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)) + { + case 0: + cbSample = 1; + break; + case 1: + cbSample = 2; + break; + case 4: + cbSample = 4; + break; + default: + AssertMsgFailed(("Unsupported bits per sample %x\n", + EXTRACT_VALUE(u16SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))); + rc = VERR_NOT_SUPPORTED; + break; + } + + if (RT_SUCCESS(rc)) + { + PDMAudioPropsInit(pProps, cbSample, true /*fSigned*/, (u16SDFMT & 0xf) + 1 /*cChannels*/, u32Hz * u32HzMult / u32HzDiv); + /** @todo is there anything we need to / can do about channel assignments? */ + } + +# undef EXTRACT_VALUE + return rc; +} + +# ifdef LOG_ENABLED +void hdaR3BDLEDumpAll(PPDMDEVINS pDevIns, PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE) +{ + LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE)); + if (!u64BDLBase) + return; + + uint32_t cbBDLE = 0; + for (uint16_t i = 0; i < cBDLE; i++) + { + HDABDLEDESC bd; + PDMDevHlpPhysRead(pDevIns, u64BDLBase + i * sizeof(HDABDLEDESC), &bd, sizeof(bd)); + + LogFunc(("\t#%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n", + i, bd.u64BufAddr, bd.u32BufSize, bd.fFlags & HDA_BDLE_F_IOC)); + + cbBDLE += bd.u32BufSize; + } + + LogFlowFunc(("Total: %RU32 bytes\n", cbBDLE)); + + if (!pThis->u64DPBase) /* No DMA base given? Bail out. */ + return; + + LogFlowFunc(("DMA counters:\n")); + + for (int i = 0; i < cBDLE; i++) + { + uint32_t uDMACnt; + PDMDevHlpPhysRead(pDevIns, (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)), + &uDMACnt, sizeof(uDMACnt)); + + LogFlowFunc(("\t#%03d DMA @ 0x%x\n", i , uDMACnt)); + } +} +# endif /* LOG_ENABLED */ + + +/** * Appends a item to the scheduler. * * @returns VBox status code. @@ -793,6 +909,49 @@ int hdaR3StreamSetUp(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShar return rc; } + +/** + * Worker for hdaR3StreamReset(). + * + * @returns The default mixer sink, NULL if none found. + * @param pThisCC The ring-3 HDA device state. + * @param uSD SD# to return mixer sink for. + * NULL if not found / handled. + */ +static PHDAMIXERSINK hdaR3GetDefaultSink(PHDASTATER3 pThisCC, uint8_t uSD) +{ + if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN) + { + const uint8_t uFirstSDI = 0; + + if (uSD == uFirstSDI) /* First SDI. */ + return &pThisCC->SinkLineIn; +# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN + if (uSD == uFirstSDI + 1) + return &pThisCC->SinkMicIn; +# else + /* If we don't have a dedicated Mic-In sink, use the always present Line-In sink. */ + return &pThisCC->SinkLineIn; +# endif + } + else + { + const uint8_t uFirstSDO = HDA_MAX_SDI; + + if (uSD == uFirstSDO) + return &pThisCC->SinkFront; +# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND + if (uSD == uFirstSDO + 1) + return &pThisCC->SinkCenterLFE; + if (uSD == uFirstSDO + 2) + return &pThisCC->SinkRear; +# endif + } + + return NULL; +} + + /** * Resets an HDA stream. * diff --git a/src/VBox/Devices/Audio/DevHdaStream.h b/src/VBox/Devices/Audio/DevHdaStream.h index ff6f9338c12..d1b46037ca6 100644 --- a/src/VBox/Devices/Audio/DevHdaStream.h +++ b/src/VBox/Devices/Audio/DevHdaStream.h @@ -336,6 +336,14 @@ uint64_t hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PH DECLCALLBACK(void) hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser); /** @} */ +/** @name Helper functions associated with the stream code. + * @{ */ +int hdaR3SDFMTToPCMProps(uint16_t u16SDFMT, PPDMAUDIOPCMPROPS pProps); +# ifdef LOG_ENABLED +void hdaR3BDLEDumpAll(PPDMDEVINS pDevIns, PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE); +# endif +/** @} */ + #endif /* IN_RING3 */ #endif /* !VBOX_INCLUDED_SRC_Audio_DevHdaStream_h */ |